Merge branch 'main' into feat/mass-import
This commit is contained in:
@@ -230,7 +230,7 @@ class CollectionScene extends React.Component<Props> {
|
||||
)}
|
||||
</Wrapper>
|
||||
<Modal
|
||||
title={t("Collection permissions")}
|
||||
title={t("Collection members")}
|
||||
onRequestClose={this.handlePermissionsModalClose}
|
||||
isOpen={this.permissionsModalOpen}
|
||||
>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { observable } from "mobx";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { withTranslation, Trans, type TFunction } from "react-i18next";
|
||||
import AuthStore from "stores/AuthStore";
|
||||
import UiStore from "stores/UiStore";
|
||||
import Collection from "models/Collection";
|
||||
import Button from "components/Button";
|
||||
@@ -17,6 +18,7 @@ import Switch from "components/Switch";
|
||||
type Props = {
|
||||
collection: Collection,
|
||||
ui: UiStore,
|
||||
auth: AuthStore,
|
||||
onSubmit: () => void,
|
||||
t: TFunction,
|
||||
};
|
||||
@@ -24,6 +26,7 @@ type Props = {
|
||||
@observer
|
||||
class CollectionEdit extends React.Component<Props> {
|
||||
@observable name: string = this.props.collection.name;
|
||||
@observable sharing: boolean = this.props.collection.sharing;
|
||||
@observable description: string = this.props.collection.description;
|
||||
@observable icon: string = this.props.collection.icon;
|
||||
@observable color: string = this.props.collection.color || "#4E5C6E";
|
||||
@@ -44,6 +47,7 @@ class CollectionEdit extends React.Component<Props> {
|
||||
icon: this.icon,
|
||||
color: this.color,
|
||||
private: this.private,
|
||||
sharing: this.sharing,
|
||||
sort: this.sort,
|
||||
});
|
||||
this.props.onSubmit();
|
||||
@@ -82,8 +86,13 @@ class CollectionEdit extends React.Component<Props> {
|
||||
this.private = ev.target.checked;
|
||||
};
|
||||
|
||||
handleSharingChange = (ev: SyntheticInputEvent<*>) => {
|
||||
this.sharing = ev.target.checked;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { auth, t } = this.props;
|
||||
const teamSharingEnabled = !!auth.team && auth.team.sharing;
|
||||
|
||||
return (
|
||||
<Flex column>
|
||||
@@ -140,6 +149,25 @@ class CollectionEdit extends React.Component<Props> {
|
||||
A private collection will only be visible to invited team members.
|
||||
</Trans>
|
||||
</HelpText>
|
||||
<Switch
|
||||
id="sharing"
|
||||
label={t("Public document sharing")}
|
||||
onChange={this.handleSharingChange}
|
||||
checked={this.sharing && teamSharingEnabled}
|
||||
disabled={!teamSharingEnabled}
|
||||
/>
|
||||
<HelpText>
|
||||
{teamSharingEnabled ? (
|
||||
<Trans>
|
||||
When enabled, documents can be shared publicly on the internet.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
Public sharing is currently disabled in the team security
|
||||
settings.
|
||||
</Trans>
|
||||
)}
|
||||
</HelpText>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={this.isSaving || !this.props.collection.name}
|
||||
@@ -152,4 +180,6 @@ class CollectionEdit extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export default withTranslation()<CollectionEdit>(inject("ui")(CollectionEdit));
|
||||
export default withTranslation()<CollectionEdit>(
|
||||
inject("ui", "auth")(CollectionEdit)
|
||||
);
|
||||
|
||||
@@ -3,8 +3,9 @@ import { intersection } from "lodash";
|
||||
import { observable } from "mobx";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import * as React from "react";
|
||||
import { withTranslation, type TFunction } from "react-i18next";
|
||||
import { withTranslation, type TFunction, Trans } from "react-i18next";
|
||||
import { withRouter, type RouterHistory } from "react-router-dom";
|
||||
import AuthStore from "stores/AuthStore";
|
||||
import CollectionsStore from "stores/CollectionsStore";
|
||||
import UiStore from "stores/UiStore";
|
||||
import Collection from "models/Collection";
|
||||
@@ -18,6 +19,7 @@ import Switch from "components/Switch";
|
||||
|
||||
type Props = {
|
||||
history: RouterHistory,
|
||||
auth: AuthStore,
|
||||
ui: UiStore,
|
||||
collections: CollectionsStore,
|
||||
onSubmit: () => void,
|
||||
@@ -30,6 +32,7 @@ class CollectionNew extends React.Component<Props> {
|
||||
@observable description: string = "";
|
||||
@observable icon: string = "";
|
||||
@observable color: string = "#4E5C6E";
|
||||
@observable sharing: boolean = true;
|
||||
@observable private: boolean = false;
|
||||
@observable isSaving: boolean;
|
||||
hasOpenedIconPicker: boolean = false;
|
||||
@@ -41,6 +44,7 @@ class CollectionNew extends React.Component<Props> {
|
||||
{
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
sharing: this.sharing,
|
||||
icon: this.icon,
|
||||
color: this.color,
|
||||
private: this.private,
|
||||
@@ -59,7 +63,7 @@ class CollectionNew extends React.Component<Props> {
|
||||
}
|
||||
};
|
||||
|
||||
handleNameChange = (ev: SyntheticInputEvent<*>) => {
|
||||
handleNameChange = (ev: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
this.name = ev.target.value;
|
||||
|
||||
// If the user hasn't picked an icon yet, go ahead and suggest one based on
|
||||
@@ -90,24 +94,31 @@ class CollectionNew extends React.Component<Props> {
|
||||
this.description = getValue();
|
||||
};
|
||||
|
||||
handlePrivateChange = (ev: SyntheticInputEvent<*>) => {
|
||||
handlePrivateChange = (ev: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
this.private = ev.target.checked;
|
||||
};
|
||||
|
||||
handleSharingChange = (ev: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
this.sharing = ev.target.checked;
|
||||
};
|
||||
|
||||
handleChange = (color: string, icon: string) => {
|
||||
this.color = color;
|
||||
this.icon = icon;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { t } = this.props;
|
||||
const { t, auth } = this.props;
|
||||
const teamSharingEnabled = !!auth.team && auth.team.sharing;
|
||||
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<HelpText>
|
||||
{t(
|
||||
"Collections are for grouping your knowledge base. They work best when organized around a topic or internal team — Product or Engineering for example."
|
||||
)}
|
||||
<Trans>
|
||||
Collections are for grouping your knowledge base. They work best
|
||||
when organized around a topic or internal team — Product or
|
||||
Engineering for example.
|
||||
</Trans>
|
||||
</HelpText>
|
||||
<Flex>
|
||||
<Input
|
||||
@@ -142,10 +153,25 @@ class CollectionNew extends React.Component<Props> {
|
||||
checked={this.private}
|
||||
/>
|
||||
<HelpText>
|
||||
{t(
|
||||
"A private collection will only be visible to invited team members."
|
||||
)}
|
||||
<Trans>
|
||||
A private collection will only be visible to invited team members.
|
||||
</Trans>
|
||||
</HelpText>
|
||||
{teamSharingEnabled && (
|
||||
<>
|
||||
<Switch
|
||||
id="sharing"
|
||||
label={t("Public document sharing")}
|
||||
onChange={this.handleSharingChange}
|
||||
checked={this.sharing}
|
||||
/>
|
||||
<HelpText>
|
||||
<Trans>
|
||||
When enabled, documents can be shared publicly on the internet.
|
||||
</Trans>
|
||||
</HelpText>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Button type="submit" disabled={this.isSaving || !this.name}>
|
||||
{this.isSaving ? `${t("Creating")}…` : t("Create")}
|
||||
@@ -156,5 +182,5 @@ class CollectionNew extends React.Component<Props> {
|
||||
}
|
||||
|
||||
export default withTranslation()<CollectionNew>(
|
||||
inject("collections", "ui")(withRouter(CollectionNew))
|
||||
inject("collections", "ui", "auth")(withRouter(CollectionNew))
|
||||
);
|
||||
|
||||
@@ -126,7 +126,7 @@ class Header extends React.Component<Props> {
|
||||
const isNew = document.isNew;
|
||||
const isTemplate = document.isTemplate;
|
||||
const can = policies.abilities(document.id);
|
||||
const canShareDocuments = auth.team && auth.team.sharing && can.share;
|
||||
const canShareDocument = auth.team && auth.team.sharing && can.share;
|
||||
const canToggleEmbeds = auth.team && auth.team.documentEmbeds;
|
||||
const canEdit = can.update && !isEditing;
|
||||
|
||||
@@ -200,7 +200,7 @@ class Header extends React.Component<Props> {
|
||||
<TemplatesMenu document={document} />
|
||||
</Action>
|
||||
)}
|
||||
{!isEditing && canShareDocuments && (
|
||||
{!isEditing && canShareDocument && (
|
||||
<Action>
|
||||
<Tooltip
|
||||
tooltip={
|
||||
|
||||
@@ -4,12 +4,13 @@ import { observable } from "mobx";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import { PlusIcon } from "outline-icons";
|
||||
import * as React from "react";
|
||||
import { withTranslation, type TFunction, Trans } from "react-i18next";
|
||||
import { type Match } from "react-router-dom";
|
||||
|
||||
import AuthStore from "stores/AuthStore";
|
||||
import PoliciesStore from "stores/PoliciesStore";
|
||||
import UsersStore from "stores/UsersStore";
|
||||
import Invite from "scenes/Invite";
|
||||
import Bubble from "components/Bubble";
|
||||
import Button from "components/Button";
|
||||
import CenteredContent from "components/CenteredContent";
|
||||
import Empty from "components/Empty";
|
||||
@@ -27,12 +28,20 @@ type Props = {
|
||||
users: UsersStore,
|
||||
policies: PoliciesStore,
|
||||
match: Match,
|
||||
t: TFunction,
|
||||
};
|
||||
|
||||
@observer
|
||||
class People extends React.Component<Props> {
|
||||
@observable inviteModalOpen: boolean = false;
|
||||
|
||||
componentDidMount() {
|
||||
const { team } = this.props.auth;
|
||||
if (team) {
|
||||
this.props.users.fetchCounts(team.id);
|
||||
}
|
||||
}
|
||||
|
||||
handleInviteModalOpen = () => {
|
||||
this.inviteModalOpen = true;
|
||||
};
|
||||
@@ -46,7 +55,7 @@ class People extends React.Component<Props> {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { auth, policies, match } = this.props;
|
||||
const { auth, policies, match, t } = this.props;
|
||||
const { filter } = match.params;
|
||||
const currentUser = auth.user;
|
||||
const team = auth.team;
|
||||
@@ -65,15 +74,18 @@ class People extends React.Component<Props> {
|
||||
}
|
||||
|
||||
const can = policies.abilities(team.id);
|
||||
const { counts } = this.props.users;
|
||||
|
||||
return (
|
||||
<CenteredContent>
|
||||
<PageTitle title="People" />
|
||||
<h1>People</h1>
|
||||
<PageTitle title={t("People")} />
|
||||
<h1>{t("People")}</h1>
|
||||
<HelpText>
|
||||
Everyone that has signed into Outline appears here. It’s possible that
|
||||
there are other users who have access through {team.signinMethods} but
|
||||
haven’t signed in yet.
|
||||
<Trans>
|
||||
Everyone that has signed into Outline appears here. It’s possible
|
||||
that there are other users who have access through{" "}
|
||||
{team.signinMethods} but haven’t signed in yet.
|
||||
</Trans>
|
||||
</HelpText>
|
||||
<Button
|
||||
type="button"
|
||||
@@ -84,37 +96,36 @@ class People extends React.Component<Props> {
|
||||
icon={<PlusIcon />}
|
||||
neutral
|
||||
>
|
||||
Invite people…
|
||||
{t("Invite people")}…
|
||||
</Button>
|
||||
|
||||
<Tabs>
|
||||
<Tab to="/settings/people" exact>
|
||||
Active
|
||||
{t("Active")} <Bubble count={counts.active} />
|
||||
</Tab>
|
||||
<Tab to="/settings/people/admins" exact>
|
||||
Admins
|
||||
{t("Admins")} <Bubble count={counts.admins} />
|
||||
</Tab>
|
||||
{can.update && (
|
||||
<Tab to="/settings/people/suspended" exact>
|
||||
Suspended
|
||||
{t("Suspended")} <Bubble count={counts.suspended} />
|
||||
</Tab>
|
||||
)}
|
||||
<Tab to="/settings/people/all" exact>
|
||||
Everyone
|
||||
{t("Everyone")} <Bubble count={counts.all - counts.invited} />
|
||||
</Tab>
|
||||
|
||||
{can.invite && (
|
||||
<>
|
||||
<Separator />
|
||||
<Tab to="/settings/people/invited" exact>
|
||||
Invited
|
||||
{t("Invited")} <Bubble count={counts.invited} />
|
||||
</Tab>
|
||||
</>
|
||||
)}
|
||||
</Tabs>
|
||||
<PaginatedList
|
||||
items={users}
|
||||
empty={<Empty>No people to see here.</Empty>}
|
||||
empty={<Empty>{t("No people to see here.")}</Empty>}
|
||||
fetch={this.fetchPage}
|
||||
renderItem={(item) => (
|
||||
<UserListItem
|
||||
@@ -126,7 +137,7 @@ class People extends React.Component<Props> {
|
||||
/>
|
||||
|
||||
<Modal
|
||||
title="Invite people"
|
||||
title={t("Invite people")}
|
||||
onRequestClose={this.handleInviteModalClose}
|
||||
isOpen={this.inviteModalOpen}
|
||||
>
|
||||
@@ -137,4 +148,8 @@ class People extends React.Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export default inject("auth", "users", "policies")(People);
|
||||
export default inject(
|
||||
"auth",
|
||||
"users",
|
||||
"policies"
|
||||
)(withTranslation()<People>(People));
|
||||
|
||||
Reference in New Issue
Block a user