mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
1a893b0e45
Adds group sync from external authentication providers, allowing team group memberships to be automatically managed based on provider data on sign-in in the future.
142 lines
3.9 KiB
TypeScript
142 lines
3.9 KiB
TypeScript
import * as React from "react";
|
|
import { EditIcon, GroupIcon, TrashIcon } from "outline-icons";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useHistory } from "react-router-dom";
|
|
import type Group from "~/models/Group";
|
|
import {
|
|
DeleteGroupDialog,
|
|
EditGroupDialog,
|
|
} from "~/scenes/Settings/components/GroupDialogs";
|
|
import usePolicy from "~/hooks/usePolicy";
|
|
import useStores from "~/hooks/useStores";
|
|
import {
|
|
ActionSeparator,
|
|
createAction,
|
|
createExternalLinkAction,
|
|
} from "~/actions";
|
|
import { GroupSection } from "~/actions/sections";
|
|
import { useMenuAction } from "~/hooks/useMenuAction";
|
|
import { settingsPath } from "~/utils/routeHelpers";
|
|
|
|
interface Options {
|
|
/** Whether to hide the "Members" navigation action. */
|
|
hideMembers?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Hook that constructs the action menu for group management operations.
|
|
*
|
|
* @param targetGroup - the group to build actions for, or null to skip.
|
|
* @param options - optional configuration for the menu.
|
|
* @returns action with children for use in menus, or undefined if group is null.
|
|
*/
|
|
export function useGroupMenuActions(
|
|
targetGroup: Group | null,
|
|
options?: Options
|
|
) {
|
|
const { t } = useTranslation();
|
|
const { dialogs } = useStores();
|
|
const history = useHistory();
|
|
const can = usePolicy(targetGroup ?? ({} as Group));
|
|
|
|
const navigateToMembers = React.useCallback(() => {
|
|
if (!targetGroup) {
|
|
return;
|
|
}
|
|
history.push(settingsPath("groups", targetGroup.id, "members"));
|
|
}, [targetGroup, history]);
|
|
|
|
const openEditDialog = React.useCallback(() => {
|
|
if (!targetGroup) {
|
|
return;
|
|
}
|
|
dialogs.openModal({
|
|
title: t("Edit group"),
|
|
content: (
|
|
<EditGroupDialog
|
|
group={targetGroup}
|
|
onSubmit={dialogs.closeAllModals}
|
|
/>
|
|
),
|
|
});
|
|
}, [t, targetGroup, dialogs]);
|
|
|
|
const openDeleteDialog = React.useCallback(() => {
|
|
if (!targetGroup) {
|
|
return;
|
|
}
|
|
dialogs.openModal({
|
|
title: t("Delete group"),
|
|
content: (
|
|
<DeleteGroupDialog
|
|
group={targetGroup}
|
|
onSubmit={dialogs.closeAllModals}
|
|
/>
|
|
),
|
|
});
|
|
}, [t, targetGroup, dialogs]);
|
|
|
|
const actionList = React.useMemo(
|
|
() =>
|
|
!targetGroup
|
|
? []
|
|
: [
|
|
...(options?.hideMembers
|
|
? []
|
|
: [
|
|
createAction({
|
|
name: t("Members"),
|
|
icon: <GroupIcon />,
|
|
section: GroupSection,
|
|
visible: can.read,
|
|
perform: navigateToMembers,
|
|
}),
|
|
ActionSeparator,
|
|
]),
|
|
createAction({
|
|
name: `${t("Edit")}…`,
|
|
icon: <EditIcon />,
|
|
section: GroupSection,
|
|
visible: can.update,
|
|
perform: openEditDialog,
|
|
}),
|
|
createAction({
|
|
name: `${t("Delete")}…`,
|
|
icon: <TrashIcon />,
|
|
section: GroupSection,
|
|
visible: can.delete,
|
|
dangerous: true,
|
|
perform: openDeleteDialog,
|
|
}),
|
|
ActionSeparator,
|
|
createExternalLinkAction({
|
|
name: targetGroup.externalId ?? "",
|
|
section: GroupSection,
|
|
visible: !!targetGroup.externalId,
|
|
disabled: true,
|
|
url: "",
|
|
}),
|
|
createExternalLinkAction({
|
|
name: `External ID: ${targetGroup.externalGroup?.externalId ?? ""}`,
|
|
section: GroupSection,
|
|
visible: !!targetGroup.externalGroup?.externalId,
|
|
disabled: true,
|
|
url: "",
|
|
}),
|
|
],
|
|
[
|
|
t,
|
|
targetGroup,
|
|
can.read,
|
|
can.update,
|
|
can.delete,
|
|
options?.hideMembers,
|
|
navigateToMembers,
|
|
openEditDialog,
|
|
openDeleteDialog,
|
|
]
|
|
);
|
|
|
|
return useMenuAction(actionList);
|
|
}
|