@burdenoff/microfe-cosmicintersection 2026.1012.1 → 2026.1030.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cosmicintersection/lib/assistantAwareDialog.d.ts +42 -0
- package/dist/cosmicintersection/lib/assistantAwareDialog.d.ts.map +1 -0
- package/dist/cosmicintersection/lib/assistantAwareDialog.js +12 -0
- package/dist/cosmicintersection/lib/assistantAwareDialog.js.map +1 -0
- package/dist/cosmicintersection/lib/useSelectedRecord.d.ts +20 -0
- package/dist/cosmicintersection/lib/useSelectedRecord.d.ts.map +1 -0
- package/dist/cosmicintersection/lib/useSelectedRecord.js +19 -0
- package/dist/cosmicintersection/lib/useSelectedRecord.js.map +1 -0
- package/dist/cosmicintersection/pages/access/AccessPage.d.ts.map +1 -1
- package/dist/cosmicintersection/pages/access/AccessPage.js +239 -226
- package/dist/cosmicintersection/pages/access/AccessPage.js.map +1 -1
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.d.ts.map +1 -1
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js +200 -196
- package/dist/cosmicintersection/pages/analyses/AnalysesPage.js.map +1 -1
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.d.ts.map +1 -1
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js +188 -175
- package/dist/cosmicintersection/pages/datasets/DatasetDetailPage.js.map +1 -1
- package/dist/cosmicintersection/pages/releases/ReleasesPage.d.ts.map +1 -1
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js +205 -201
- package/dist/cosmicintersection/pages/releases/ReleasesPage.js.map +1 -1
- package/dist/utils/pageContext.d.ts +33 -7
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +75 -33
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/access/AccessPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { KeyRound, ShieldCheck } from 'lucide-react';\nimport {\n Badge,\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAccessGrantsQuery,\n useCosDatasetsQuery,\n useCosGrantAccessMutation,\n useCosRevokeAccessMutation,\n type CosDataAccessGrant,\n type CosGrantAccessInput,\n type CosGrantStatus,\n} from '../../api/cosmicApi';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n StatusBadge,\n formatEnumLabel,\n} from '../../components';\nimport { ActionMenu } from '../../components/ActionMenu';\nimport { EntityTagsField } from '../../components/EntityTagsField';\nimport { notify } from '../../lib/toast';\nimport { useTr } from '../../../shared/hooks/useTr';\n\nconst ALL = 'ALL';\nconst GRANT_STATUSES: CosGrantStatus[] = ['PENDING', 'ACTIVE', 'EXPIRED', 'REVOKED'];\n\n/** Only live grants can be revoked. */\nfunction canRevoke(status: CosGrantStatus): boolean {\n return status === 'ACTIVE' || status === 'PENDING';\n}\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n return '—';\n }\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\ninterface GrantFormState {\n datasetId: string;\n granteeId: string;\n scopes: string[];\n reason: string;\n expiresAt: string;\n}\n\nconst EMPTY_FORM: GrantFormState = {\n datasetId: '',\n granteeId: '',\n scopes: [],\n reason: '',\n expiresAt: '',\n};\n\nexport default function AccessPage() {\n const tr = useTr();\n const [datasetFilter, setDatasetFilter] = useState<string>(ALL);\n const [statusFilter, setStatusFilter] = useState<string>(ALL);\n\n const datasetsQuery = useCosDatasetsQuery({ pagination: { limit: 50, offset: 0 } });\n const datasets = useMemo(\n () => datasetsQuery.data?.cosListDatasets.items ?? [],\n [datasetsQuery.data]\n );\n const datasetName = useMemo(() => {\n const map = new Map<string, string>();\n for (const dataset of datasets) {\n map.set(dataset.id, dataset.name);\n }\n return map;\n }, [datasets]);\n\n const { data, loading, error, refetch } = useCosAccessGrantsQuery({\n datasetId: datasetFilter === ALL ? undefined : datasetFilter,\n status: statusFilter === ALL ? undefined : (statusFilter as CosGrantStatus),\n });\n const grants = useMemo(() => data?.cosListAccessGrants ?? [], [data]);\n\n const [grantAccess, { loading: granting }] = useCosGrantAccessMutation();\n const [revokeAccess] = useCosRevokeAccessMutation();\n\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<GrantFormState>(EMPTY_FORM);\n\n const openGrantDialog = () => {\n setForm({\n ...EMPTY_FORM,\n datasetId: datasetFilter === ALL ? '' : datasetFilter,\n });\n setDialogOpen(true);\n };\n\n const setField = <K extends keyof GrantFormState>(field: K, value: GrantFormState[K]) => {\n setForm((prev) => ({ ...prev, [field]: value }));\n };\n\n const submitGrant = async () => {\n if (!form.datasetId) {\n notify.error(\n tr('cosmicintersection.pages.access.datasetRequired', 'Dataset is required'),\n tr(\n 'cosmicintersection.pages.access.datasetRequiredDescription',\n 'Choose which dataset this grant applies to.'\n )\n );\n return;\n }\n if (!form.granteeId.trim()) {\n notify.error(\n tr('cosmicintersection.pages.access.granteeRequired', 'Grantee is required'),\n tr(\n 'cosmicintersection.pages.access.granteeRequiredDescription',\n 'Enter the workspace User ID to grant access to.'\n )\n );\n return;\n }\n\n let expiresAt: string | undefined;\n if (form.expiresAt) {\n const parsed = new Date(form.expiresAt);\n if (Number.isNaN(parsed.getTime())) {\n notify.error(\n tr('cosmicintersection.pages.access.invalidExpiry', 'Invalid expiry'),\n tr(\n 'cosmicintersection.pages.access.invalidExpiryDescription',\n 'Enter a valid expiry date or leave it blank.'\n )\n );\n return;\n }\n expiresAt = parsed.toISOString();\n }\n\n const input: CosGrantAccessInput = {\n datasetId: form.datasetId,\n granteeId: form.granteeId.trim(),\n scopes: form.scopes.length ? form.scopes : undefined,\n reason: form.reason.trim() || undefined,\n expiresAt,\n };\n\n const response = await grantAccess({ variables: { input } });\n if (response.data?.cosGrantAccess?.id) {\n notify.success(tr('cosmicintersection.pages.access.accessGranted', 'Access granted'));\n setDialogOpen(false);\n setForm(EMPTY_FORM);\n await refetch();\n }\n };\n\n const handleRevoke = async (grant: CosDataAccessGrant) => {\n const response = await revokeAccess({ variables: { id: grant.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosRevokeAccess?.id) {\n notify.error(\n tr('cosmicintersection.pages.access.revokeError', 'Could not revoke grant'),\n tr(\n 'cosmicintersection.pages.access.revokeErrorDescription',\n 'The server did not confirm the change.'\n )\n );\n throw new Error('Revoke not confirmed');\n }\n notify.success(tr('cosmicintersection.pages.access.accessRevoked', 'Access revoked'));\n await refetch();\n };\n\n const grantButton = (\n <Button type=\"button\" onClick={openGrantDialog}>\n <KeyRound className=\"size-4\" />\n {tr('cosmicintersection.pages.access.grantAccess', 'Grant access')}\n </Button>\n );\n\n const showDatasetColumn = datasetFilter === ALL;\n\n const renderBody = () => {\n if (loading) {\n return (\n <LoadingState\n variant=\"rows\"\n rows={6}\n label={tr('cosmicintersection.pages.access.loading', 'Loading access grants…')}\n />\n );\n }\n if (error) {\n return <ErrorState message={error.message} onRetry={() => void refetch()} />;\n }\n if (grants.length === 0) {\n const filtered = datasetFilter !== ALL || statusFilter !== ALL;\n return (\n <EmptyState\n icon={ShieldCheck}\n title={\n filtered\n ? tr(\n 'cosmicintersection.pages.access.emptyFilterTitle',\n 'No grants match these filters'\n )\n : tr('cosmicintersection.pages.access.emptyTitle', 'No access grants yet')\n }\n description={\n filtered\n ? tr(\n 'cosmicintersection.pages.access.emptyFilterDescription',\n 'Try clearing the dataset or status filter to see more grants.'\n )\n : tr(\n 'cosmicintersection.pages.access.emptyDescription',\n 'Grant a workspace member scoped access to a restricted or embargoed dataset.'\n )\n }\n action={filtered ? undefined : grantButton}\n />\n );\n }\n\n return (\n <>\n {/* Desktop table */}\n <div className=\"hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n {showDatasetColumn ? <TableHead>Dataset</TableHead> : null}\n <TableHead>Grantee</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Scopes</TableHead>\n <TableHead>Reason</TableHead>\n <TableHead>Granted</TableHead>\n <TableHead>Expires</TableHead>\n <TableHead>Revoked</TableHead>\n <TableHead className=\"text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {grants.map((grant) => (\n <TableRow key={grant.id}>\n {showDatasetColumn ? (\n <TableCell className=\"max-w-[12rem]\">\n <span className=\"line-clamp-1 text-sm text-text-primary\">\n {datasetName.get(grant.datasetId) ?? (\n <span className=\"font-mono text-xs text-text-secondary\">\n {grant.datasetId}\n </span>\n )}\n </span>\n </TableCell>\n ) : null}\n <TableCell className=\"max-w-[12rem]\">\n <span className=\"block truncate font-mono text-xs text-text-primary\">\n {grant.granteeId}\n </span>\n </TableCell>\n <TableCell>\n <StatusBadge status={grant.status} />\n </TableCell>\n <TableCell>\n <div className=\"flex max-w-[12rem] flex-wrap gap-1\">\n {grant.scopes.length === 0 ? (\n <span className=\"text-xs text-text-secondary\">—</span>\n ) : (\n grant.scopes.map((scope) => (\n <Badge key={scope} variant=\"outline\" className=\"text-xs\">\n {scope}\n </Badge>\n ))\n )}\n </div>\n </TableCell>\n <TableCell className=\"max-w-[14rem]\">\n {grant.reason ? (\n <span className=\"line-clamp-1 text-sm text-text-secondary\">\n {grant.reason}\n </span>\n ) : (\n <span className=\"text-sm text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(grant.grantedAt)}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(grant.expiresAt)}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(grant.revokedAt)}\n </TableCell>\n <TableCell className=\"text-right\">\n {canRevoke(grant.status) ? (\n <ActionMenu\n ariaLabel={`Actions for grant to ${grant.granteeId}`}\n entityName={grant.granteeId}\n onDelete={() => handleRevoke(grant)}\n deleteLabel=\"Revoke grant\"\n />\n ) : (\n <span className=\"text-xs text-text-secondary\">—</span>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile card list */}\n <ul className=\"space-y-3 md:hidden\">\n {grants.map((grant) => (\n <li key={grant.id} className=\"rounded-card border border-border-default bg-bg-elevated\">\n <div className=\"flex items-start justify-between gap-2 p-4\">\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {showDatasetColumn ? (\n <span className=\"truncate text-sm font-medium text-text-primary\">\n {datasetName.get(grant.datasetId) ?? 'Dataset'}\n </span>\n ) : null}\n <StatusBadge status={grant.status} />\n </div>\n\n <div>\n <p className=\"text-xs text-text-secondary\">Grantee (User ID)</p>\n <p className=\"truncate font-mono text-xs text-text-primary\">\n {grant.granteeId}\n </p>\n </div>\n\n {grant.scopes.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {grant.scopes.map((scope) => (\n <Badge key={scope} variant=\"outline\" className=\"text-xs\">\n {scope}\n </Badge>\n ))}\n </div>\n ) : null}\n\n {grant.reason ? (\n <p className=\"line-clamp-2 text-xs text-text-secondary\">{grant.reason}</p>\n ) : null}\n\n <div className=\"flex flex-wrap gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Granted {formatDate(grant.grantedAt)}</span>\n <span>Expires {formatDate(grant.expiresAt)}</span>\n {grant.revokedAt ? <span>Revoked {formatDate(grant.revokedAt)}</span> : null}\n </div>\n </div>\n\n {canRevoke(grant.status) ? (\n <ActionMenu\n ariaLabel={`Actions for grant to ${grant.granteeId}`}\n entityName={grant.granteeId}\n onDelete={() => handleRevoke(grant)}\n deleteLabel=\"Revoke grant\"\n />\n ) : null}\n </div>\n </li>\n ))}\n </ul>\n </>\n );\n };\n\n return (\n <PageLayout\n title={tr('cosmicintersection.pages.access.title', 'Data access')}\n description={tr(\n 'cosmicintersection.pages.access.description',\n 'Govern who can reach restricted and embargoed datasets, with scoped, expiring grants.'\n )}\n actions={grantButton}\n >\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"w-full max-w-[18rem]\">\n <Select value={datasetFilter} onValueChange={setDatasetFilter}>\n <SelectTrigger aria-label=\"Filter by dataset\">\n <SelectValue placeholder=\"All datasets\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All datasets</SelectItem>\n {datasets.map((dataset) => (\n <SelectItem key={dataset.id} value={dataset.id}>\n {dataset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full max-w-[14rem]\">\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger aria-label=\"Filter by status\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All statuses</SelectItem>\n {GRANT_STATUSES.map((status) => (\n <SelectItem key={status} value={status}>\n {formatEnumLabel(status)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {renderBody()}\n </div>\n\n {/* Grant access dialog */}\n <Dialog\n open={dialogOpen}\n onOpenChange={(open) => (open || granting ? setDialogOpen(open) : setDialogOpen(false))}\n >\n <DialogContent className=\"max-h-[85vh] max-w-md overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {tr('cosmicintersection.pages.access.grantDataAccess', 'Grant data access')}\n </DialogTitle>\n <DialogDescription>\n {tr(\n 'cosmicintersection.pages.access.grantDataAccessDescription',\n \"Give a workspace member scoped access to a dataset. Access is identified by the member's User ID.\"\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-dataset\">\n {tr('cosmicintersection.pages.access.dataset', 'Dataset')}\n </Label>\n <Select\n value={form.datasetId || undefined}\n onValueChange={(value) => setField('datasetId', value)}\n >\n <SelectTrigger\n id=\"grant-dataset\"\n aria-label={tr('cosmicintersection.pages.access.dataset', 'Dataset')}\n >\n <SelectValue\n placeholder={tr(\n 'cosmicintersection.pages.access.selectDataset',\n 'Select a dataset'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {datasets.map((dataset) => (\n <SelectItem key={dataset.id} value={dataset.id}>\n {dataset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-grantee\">\n {tr('cosmicintersection.pages.access.grantee', 'Grantee (User ID)')}\n </Label>\n <Input\n id=\"grant-grantee\"\n value={form.granteeId}\n onChange={(event) => setField('granteeId', event.target.value)}\n placeholder=\"e.g. 4fe35990-…\"\n className=\"font-mono\"\n />\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'cosmicintersection.pages.access.granteeHint',\n 'Paste the workspace member\\'s User ID. You can copy it from the member\\'s profile (\"Get ID\") or the workspace member directory.'\n )}\n </p>\n </div>\n\n <EntityTagsField\n value={form.scopes}\n onChange={(scopes) => setField('scopes', scopes)}\n label={tr('cosmicintersection.pages.access.scopes', 'Scopes')}\n placeholder=\"e.g. read, download\"\n />\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-reason\">\n {tr('cosmicintersection.pages.access.reason', 'Reason')}\n </Label>\n <Textarea\n id=\"grant-reason\"\n value={form.reason}\n onChange={(event) => setField('reason', event.target.value)}\n rows={2}\n placeholder={tr(\n 'cosmicintersection.pages.access.reasonPlaceholder',\n 'Why this member needs access.'\n )}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-expires\">\n {tr('cosmicintersection.pages.access.expiresOptional', 'Expires (optional)')}\n </Label>\n <Input\n id=\"grant-expires\"\n type=\"datetime-local\"\n value={form.expiresAt}\n onChange={(event) => setField('expiresAt', event.target.value)}\n />\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'cosmicintersection.pages.access.expiresHint',\n 'Leave blank for an open-ended grant.'\n )}\n </p>\n </div>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setDialogOpen(false)}\n disabled={granting}\n >\n {tr('cosmicintersection.common.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void submitGrant()} disabled={granting}>\n <KeyRound className=\"size-4\" />\n {granting\n ? tr('cosmicintersection.pages.access.granting', 'Granting…')\n : tr('cosmicintersection.pages.access.grantAccess', 'Grant access')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AccessPage.js","names":[],"sources":["../../../../src/cosmicintersection/pages/access/AccessPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { KeyRound, ShieldCheck } from 'lucide-react';\nimport {\n Badge,\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n Textarea,\n} from '@burdenoff/fe-libs/ui';\n\nimport {\n useCosAccessGrantsQuery,\n useCosDatasetsQuery,\n useCosGrantAccessMutation,\n useCosRevokeAccessMutation,\n type CosDataAccessGrant,\n type CosGrantAccessInput,\n type CosGrantStatus,\n} from '../../api/cosmicApi';\nimport {\n EmptyState,\n ErrorState,\n LoadingState,\n PageLayout,\n StatusBadge,\n formatEnumLabel,\n} from '../../components';\nimport { ActionMenu } from '../../components/ActionMenu';\nimport { EntityTagsField } from '../../components/EntityTagsField';\nimport { notify } from '../../lib/toast';\nimport { useSelectedRecord } from '../../lib/useSelectedRecord';\nimport { useTr } from '../../../shared/hooks/useTr';\n\nconst ALL = 'ALL';\nconst GRANT_STATUSES: CosGrantStatus[] = ['PENDING', 'ACTIVE', 'EXPIRED', 'REVOKED'];\n\n/** Only live grants can be revoked. */\nfunction canRevoke(status: CosGrantStatus): boolean {\n return status === 'ACTIVE' || status === 'PENDING';\n}\n\nfunction formatDate(value?: string | null): string {\n if (!value) {\n return '—';\n }\n const parsed = new Date(value);\n if (Number.isNaN(parsed.getTime())) {\n return '—';\n }\n return parsed.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });\n}\n\ninterface GrantFormState {\n datasetId: string;\n granteeId: string;\n scopes: string[];\n reason: string;\n expiresAt: string;\n}\n\nconst EMPTY_FORM: GrantFormState = {\n datasetId: '',\n granteeId: '',\n scopes: [],\n reason: '',\n expiresAt: '',\n};\n\nexport default function AccessPage() {\n const tr = useTr();\n // The dataset filter and the focused grant live in the URL (`?datasetId=`,\n // `?id=`) so the assistant's page context resolves \"this dataset\" and \"this\n // grant\" (COSMIC_DATASET / COSMIC_GRANT) and the view is linkable.\n const { selectedId: datasetParam, select: selectDataset } = useSelectedRecord('datasetId');\n const datasetFilter = datasetParam ?? ALL;\n const setDatasetFilter = (value: string) => selectDataset(value === ALL ? null : value);\n const { selectedId: focusedGrantId, select: focusGrant } = useSelectedRecord('id');\n const toggleFocus = (grant: CosDataAccessGrant) =>\n focusGrant(focusedGrantId === grant.id ? null : grant.id);\n const [statusFilter, setStatusFilter] = useState<string>(ALL);\n\n const datasetsQuery = useCosDatasetsQuery({ pagination: { limit: 50, offset: 0 } });\n const datasets = useMemo(\n () => datasetsQuery.data?.cosListDatasets.items ?? [],\n [datasetsQuery.data]\n );\n const datasetName = useMemo(() => {\n const map = new Map<string, string>();\n for (const dataset of datasets) {\n map.set(dataset.id, dataset.name);\n }\n return map;\n }, [datasets]);\n\n const { data, loading, error, refetch } = useCosAccessGrantsQuery({\n datasetId: datasetFilter === ALL ? undefined : datasetFilter,\n status: statusFilter === ALL ? undefined : (statusFilter as CosGrantStatus),\n });\n const grants = useMemo(() => data?.cosListAccessGrants ?? [], [data]);\n\n const [grantAccess, { loading: granting }] = useCosGrantAccessMutation();\n const [revokeAccess] = useCosRevokeAccessMutation();\n\n const [dialogOpen, setDialogOpen] = useState(false);\n const [form, setForm] = useState<GrantFormState>(EMPTY_FORM);\n\n const openGrantDialog = () => {\n setForm({\n ...EMPTY_FORM,\n datasetId: datasetFilter === ALL ? '' : datasetFilter,\n });\n setDialogOpen(true);\n };\n\n const setField = <K extends keyof GrantFormState>(field: K, value: GrantFormState[K]) => {\n setForm((prev) => ({ ...prev, [field]: value }));\n };\n\n const submitGrant = async () => {\n if (!form.datasetId) {\n notify.error(\n tr('cosmicintersection.pages.access.datasetRequired', 'Dataset is required'),\n tr(\n 'cosmicintersection.pages.access.datasetRequiredDescription',\n 'Choose which dataset this grant applies to.'\n )\n );\n return;\n }\n if (!form.granteeId.trim()) {\n notify.error(\n tr('cosmicintersection.pages.access.granteeRequired', 'Grantee is required'),\n tr(\n 'cosmicintersection.pages.access.granteeRequiredDescription',\n 'Enter the workspace User ID to grant access to.'\n )\n );\n return;\n }\n\n let expiresAt: string | undefined;\n if (form.expiresAt) {\n const parsed = new Date(form.expiresAt);\n if (Number.isNaN(parsed.getTime())) {\n notify.error(\n tr('cosmicintersection.pages.access.invalidExpiry', 'Invalid expiry'),\n tr(\n 'cosmicintersection.pages.access.invalidExpiryDescription',\n 'Enter a valid expiry date or leave it blank.'\n )\n );\n return;\n }\n expiresAt = parsed.toISOString();\n }\n\n const input: CosGrantAccessInput = {\n datasetId: form.datasetId,\n granteeId: form.granteeId.trim(),\n scopes: form.scopes.length ? form.scopes : undefined,\n reason: form.reason.trim() || undefined,\n expiresAt,\n };\n\n const response = await grantAccess({ variables: { input } });\n if (response.data?.cosGrantAccess?.id) {\n notify.success(tr('cosmicintersection.pages.access.accessGranted', 'Access granted'));\n setDialogOpen(false);\n setForm(EMPTY_FORM);\n await refetch();\n }\n };\n\n const handleRevoke = async (grant: CosDataAccessGrant) => {\n const response = await revokeAccess({ variables: { id: grant.id } });\n if (response.error) {\n throw new Error(response.error.message);\n }\n if (!response.data?.cosRevokeAccess?.id) {\n notify.error(\n tr('cosmicintersection.pages.access.revokeError', 'Could not revoke grant'),\n tr(\n 'cosmicintersection.pages.access.revokeErrorDescription',\n 'The server did not confirm the change.'\n )\n );\n throw new Error('Revoke not confirmed');\n }\n notify.success(tr('cosmicintersection.pages.access.accessRevoked', 'Access revoked'));\n await refetch();\n };\n\n const grantButton = (\n <Button type=\"button\" onClick={openGrantDialog}>\n <KeyRound className=\"size-4\" />\n {tr('cosmicintersection.pages.access.grantAccess', 'Grant access')}\n </Button>\n );\n\n const showDatasetColumn = datasetFilter === ALL;\n\n const renderBody = () => {\n if (loading) {\n return (\n <LoadingState\n variant=\"rows\"\n rows={6}\n label={tr('cosmicintersection.pages.access.loading', 'Loading access grants…')}\n />\n );\n }\n if (error) {\n return <ErrorState message={error.message} onRetry={() => void refetch()} />;\n }\n if (grants.length === 0) {\n const filtered = datasetFilter !== ALL || statusFilter !== ALL;\n return (\n <EmptyState\n icon={ShieldCheck}\n title={\n filtered\n ? tr(\n 'cosmicintersection.pages.access.emptyFilterTitle',\n 'No grants match these filters'\n )\n : tr('cosmicintersection.pages.access.emptyTitle', 'No access grants yet')\n }\n description={\n filtered\n ? tr(\n 'cosmicintersection.pages.access.emptyFilterDescription',\n 'Try clearing the dataset or status filter to see more grants.'\n )\n : tr(\n 'cosmicintersection.pages.access.emptyDescription',\n 'Grant a workspace member scoped access to a restricted or embargoed dataset.'\n )\n }\n action={filtered ? undefined : grantButton}\n />\n );\n }\n\n return (\n <>\n {/* Desktop table */}\n <div className=\"hidden rounded-card border border-border-default bg-bg-elevated md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n {showDatasetColumn ? <TableHead>Dataset</TableHead> : null}\n <TableHead>Grantee</TableHead>\n <TableHead>Status</TableHead>\n <TableHead>Scopes</TableHead>\n <TableHead>Reason</TableHead>\n <TableHead>Granted</TableHead>\n <TableHead>Expires</TableHead>\n <TableHead>Revoked</TableHead>\n <TableHead className=\"text-right\">Actions</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {grants.map((grant) => (\n <TableRow\n key={grant.id}\n aria-selected={focusedGrantId === grant.id}\n data-state={focusedGrantId === grant.id ? 'selected' : undefined}\n className={focusedGrantId === grant.id ? 'bg-bg-sunken' : undefined}\n >\n {showDatasetColumn ? (\n <TableCell className=\"max-w-[12rem]\">\n <span className=\"line-clamp-1 text-sm text-text-primary\">\n {datasetName.get(grant.datasetId) ?? (\n <span className=\"font-mono text-xs text-text-secondary\">\n {grant.datasetId}\n </span>\n )}\n </span>\n </TableCell>\n ) : null}\n <TableCell className=\"max-w-[12rem]\">\n <button\n type=\"button\"\n onClick={() => toggleFocus(grant)}\n aria-pressed={focusedGrantId === grant.id}\n className=\"block max-w-full truncate text-left font-mono text-xs text-text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-border-focus\"\n >\n {grant.granteeId}\n </button>\n </TableCell>\n <TableCell>\n <StatusBadge status={grant.status} />\n </TableCell>\n <TableCell>\n <div className=\"flex max-w-[12rem] flex-wrap gap-1\">\n {grant.scopes.length === 0 ? (\n <span className=\"text-xs text-text-secondary\">—</span>\n ) : (\n grant.scopes.map((scope) => (\n <Badge key={scope} variant=\"outline\" className=\"text-xs\">\n {scope}\n </Badge>\n ))\n )}\n </div>\n </TableCell>\n <TableCell className=\"max-w-[14rem]\">\n {grant.reason ? (\n <span className=\"line-clamp-1 text-sm text-text-secondary\">\n {grant.reason}\n </span>\n ) : (\n <span className=\"text-sm text-text-secondary\">—</span>\n )}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(grant.grantedAt)}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(grant.expiresAt)}\n </TableCell>\n <TableCell className=\"whitespace-nowrap text-sm text-text-secondary\">\n {formatDate(grant.revokedAt)}\n </TableCell>\n <TableCell className=\"text-right\">\n {canRevoke(grant.status) ? (\n <ActionMenu\n ariaLabel={`Actions for grant to ${grant.granteeId}`}\n entityName={grant.granteeId}\n onDelete={() => handleRevoke(grant)}\n deleteLabel=\"Revoke grant\"\n />\n ) : (\n <span className=\"text-xs text-text-secondary\">—</span>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </div>\n\n {/* Mobile card list */}\n <ul className=\"space-y-3 md:hidden\">\n {grants.map((grant) => (\n <li\n key={grant.id}\n aria-current={focusedGrantId === grant.id ? 'true' : undefined}\n className={\n focusedGrantId === grant.id\n ? 'rounded-card border border-border-focus bg-bg-sunken'\n : 'rounded-card border border-border-default bg-bg-elevated'\n }\n >\n <div className=\"flex items-start justify-between gap-2 p-4\">\n <div className=\"min-w-0 flex-1 space-y-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {showDatasetColumn ? (\n <span className=\"truncate text-sm font-medium text-text-primary\">\n {datasetName.get(grant.datasetId) ?? 'Dataset'}\n </span>\n ) : null}\n <StatusBadge status={grant.status} />\n </div>\n\n <div>\n <p className=\"text-xs text-text-secondary\">Grantee (User ID)</p>\n <button\n type=\"button\"\n onClick={() => toggleFocus(grant)}\n aria-pressed={focusedGrantId === grant.id}\n className=\"block max-w-full truncate text-left font-mono text-xs text-text-primary underline-offset-2 hover:underline\"\n >\n {grant.granteeId}\n </button>\n </div>\n\n {grant.scopes.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {grant.scopes.map((scope) => (\n <Badge key={scope} variant=\"outline\" className=\"text-xs\">\n {scope}\n </Badge>\n ))}\n </div>\n ) : null}\n\n {grant.reason ? (\n <p className=\"line-clamp-2 text-xs text-text-secondary\">{grant.reason}</p>\n ) : null}\n\n <div className=\"flex flex-wrap gap-x-3 gap-y-1 text-xs text-text-secondary\">\n <span>Granted {formatDate(grant.grantedAt)}</span>\n <span>Expires {formatDate(grant.expiresAt)}</span>\n {grant.revokedAt ? <span>Revoked {formatDate(grant.revokedAt)}</span> : null}\n </div>\n </div>\n\n {canRevoke(grant.status) ? (\n <ActionMenu\n ariaLabel={`Actions for grant to ${grant.granteeId}`}\n entityName={grant.granteeId}\n onDelete={() => handleRevoke(grant)}\n deleteLabel=\"Revoke grant\"\n />\n ) : null}\n </div>\n </li>\n ))}\n </ul>\n </>\n );\n };\n\n return (\n <PageLayout\n title={tr('cosmicintersection.pages.access.title', 'Data access')}\n description={tr(\n 'cosmicintersection.pages.access.description',\n 'Govern who can reach restricted and embargoed datasets, with scoped, expiring grants.'\n )}\n actions={grantButton}\n >\n <div className=\"space-y-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"w-full max-w-[18rem]\">\n <Select value={datasetFilter} onValueChange={setDatasetFilter}>\n <SelectTrigger aria-label=\"Filter by dataset\">\n <SelectValue placeholder=\"All datasets\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All datasets</SelectItem>\n {datasets.map((dataset) => (\n <SelectItem key={dataset.id} value={dataset.id}>\n {dataset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"w-full max-w-[14rem]\">\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger aria-label=\"Filter by status\">\n <SelectValue placeholder=\"All statuses\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={ALL}>All statuses</SelectItem>\n {GRANT_STATUSES.map((status) => (\n <SelectItem key={status} value={status}>\n {formatEnumLabel(status)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {renderBody()}\n </div>\n\n {/* Grant access dialog */}\n <Dialog\n open={dialogOpen}\n onOpenChange={(open) => (open || granting ? setDialogOpen(open) : setDialogOpen(false))}\n >\n <DialogContent className=\"max-h-[85vh] max-w-md overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {tr('cosmicintersection.pages.access.grantDataAccess', 'Grant data access')}\n </DialogTitle>\n <DialogDescription>\n {tr(\n 'cosmicintersection.pages.access.grantDataAccessDescription',\n \"Give a workspace member scoped access to a dataset. Access is identified by the member's User ID.\"\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-4\">\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-dataset\">\n {tr('cosmicintersection.pages.access.dataset', 'Dataset')}\n </Label>\n <Select\n value={form.datasetId || undefined}\n onValueChange={(value) => setField('datasetId', value)}\n >\n <SelectTrigger\n id=\"grant-dataset\"\n aria-label={tr('cosmicintersection.pages.access.dataset', 'Dataset')}\n >\n <SelectValue\n placeholder={tr(\n 'cosmicintersection.pages.access.selectDataset',\n 'Select a dataset'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n {datasets.map((dataset) => (\n <SelectItem key={dataset.id} value={dataset.id}>\n {dataset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-grantee\">\n {tr('cosmicintersection.pages.access.grantee', 'Grantee (User ID)')}\n </Label>\n <Input\n id=\"grant-grantee\"\n value={form.granteeId}\n onChange={(event) => setField('granteeId', event.target.value)}\n placeholder=\"e.g. 4fe35990-…\"\n className=\"font-mono\"\n />\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'cosmicintersection.pages.access.granteeHint',\n 'Paste the workspace member\\'s User ID. You can copy it from the member\\'s profile (\"Get ID\") or the workspace member directory.'\n )}\n </p>\n </div>\n\n <EntityTagsField\n value={form.scopes}\n onChange={(scopes) => setField('scopes', scopes)}\n label={tr('cosmicintersection.pages.access.scopes', 'Scopes')}\n placeholder=\"e.g. read, download\"\n />\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-reason\">\n {tr('cosmicintersection.pages.access.reason', 'Reason')}\n </Label>\n <Textarea\n id=\"grant-reason\"\n value={form.reason}\n onChange={(event) => setField('reason', event.target.value)}\n rows={2}\n placeholder={tr(\n 'cosmicintersection.pages.access.reasonPlaceholder',\n 'Why this member needs access.'\n )}\n />\n </div>\n\n <div className=\"space-y-1.5\">\n <Label htmlFor=\"grant-expires\">\n {tr('cosmicintersection.pages.access.expiresOptional', 'Expires (optional)')}\n </Label>\n <Input\n id=\"grant-expires\"\n type=\"datetime-local\"\n value={form.expiresAt}\n onChange={(event) => setField('expiresAt', event.target.value)}\n />\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'cosmicintersection.pages.access.expiresHint',\n 'Leave blank for an open-ended grant.'\n )}\n </p>\n </div>\n </div>\n\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setDialogOpen(false)}\n disabled={granting}\n >\n {tr('cosmicintersection.common.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void submitGrant()} disabled={granting}>\n <KeyRound className=\"size-4\" />\n {granting\n ? tr('cosmicintersection.pages.access.granting', 'Granting…')\n : tr('cosmicintersection.pages.access.grantAccess', 'Grant access')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalysesPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/analyses/AnalysesPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AnalysesPage.d.ts","sourceRoot":"","sources":["../../../../src/cosmicintersection/pages/analyses/AnalysesPage.tsx"],"names":[],"mappings":"AA2lBA,MAAM,CAAC,OAAO,UAAU,YAAY,gCAoXnC"}
|