Files
outline/app/hooks/useGroupMenuActions.tsx
Tom Moor 1a893b0e45 Group sync framework (#11684)
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.
2026-03-14 23:02:20 -04:00

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);
}