feat: add personal and group view ownership
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
FormField,
|
||||
hasScope,
|
||||
type ApiSettings,
|
||||
type AuthInfo
|
||||
} from "@govoplan/core-webui";
|
||||
import ViewsAdminPanel from "./ViewsAdminPanel";
|
||||
import type { ViewScopeType } from "../../api/views";
|
||||
|
||||
|
||||
type OwnerOption = {
|
||||
key: string;
|
||||
scopeType: Extract<ViewScopeType, "group" | "user">;
|
||||
scopeId: string;
|
||||
label: string;
|
||||
description: string;
|
||||
canWrite: boolean;
|
||||
};
|
||||
|
||||
|
||||
export default function PersonalViewsPanel({
|
||||
settings,
|
||||
auth
|
||||
}: {
|
||||
settings: ApiSettings;
|
||||
auth: AuthInfo;
|
||||
}) {
|
||||
const options = useMemo(() => ownerOptions(auth), [auth]);
|
||||
const [ownerKey, setOwnerKey] = useState(options[0]?.key ?? "");
|
||||
|
||||
useEffect(() => {
|
||||
if (!options.some((option) => option.key === ownerKey)) {
|
||||
setOwnerKey(options[0]?.key ?? "");
|
||||
}
|
||||
}, [options, ownerKey]);
|
||||
|
||||
const owner = options.find((option) => option.key === ownerKey) ?? options[0];
|
||||
if (!owner) {
|
||||
return (
|
||||
<p className="muted">
|
||||
You do not have access to personal or group View definitions.
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="views-personal-panel">
|
||||
{options.length > 1 && (
|
||||
<div className="views-owner-toolbar">
|
||||
<FormField label="View owner">
|
||||
<select
|
||||
value={owner.key}
|
||||
onChange={(event) => setOwnerKey(event.target.value)}
|
||||
>
|
||||
{options.map((option) => (
|
||||
<option key={option.key} value={option.key}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</FormField>
|
||||
</div>
|
||||
)}
|
||||
<ViewsAdminPanel
|
||||
key={owner.key}
|
||||
settings={settings}
|
||||
scopeType={owner.scopeType}
|
||||
scopeId={owner.scopeId}
|
||||
canWriteDefinitions={owner.canWrite}
|
||||
canWriteAssignments={false}
|
||||
showAssignments={false}
|
||||
embedded
|
||||
title={owner.label}
|
||||
description={owner.description}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function ownerOptions(auth: AuthInfo): OwnerOption[] {
|
||||
const tenantManager = hasScope(auth, "views:definition:write");
|
||||
const options: OwnerOption[] = [];
|
||||
if (
|
||||
tenantManager ||
|
||||
hasScope(auth, "views:personal_definition:read") ||
|
||||
hasScope(auth, "views:personal_definition:write")
|
||||
) {
|
||||
options.push({
|
||||
key: `user:${auth.user.account_id}`,
|
||||
scopeType: "user",
|
||||
scopeId: auth.user.account_id,
|
||||
label: "My Views",
|
||||
description:
|
||||
"Design personal interface projections. Publishing a View makes it available to this account.",
|
||||
canWrite:
|
||||
tenantManager ||
|
||||
hasScope(auth, "views:personal_definition:write")
|
||||
});
|
||||
}
|
||||
const canReadGroups =
|
||||
tenantManager ||
|
||||
hasScope(auth, "views:group_definition:read") ||
|
||||
hasScope(auth, "views:group_definition:write");
|
||||
if (canReadGroups) {
|
||||
for (const group of auth.groups) {
|
||||
options.push({
|
||||
key: `group:${group.id}`,
|
||||
scopeType: "group",
|
||||
scopeId: group.id,
|
||||
label: `Group: ${group.name}`,
|
||||
description:
|
||||
"Design reusable interface projections for this group. Publishing a View makes it available to all current group members.",
|
||||
canWrite:
|
||||
tenantManager ||
|
||||
hasScope(auth, "views:group_definition:write")
|
||||
});
|
||||
}
|
||||
}
|
||||
return options;
|
||||
}
|
||||
Reference in New Issue
Block a user