mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-11 03:06:54 +00:00
fix(rbac): handle permission metadata failures (#1735)
This commit is contained in:
@@ -84,7 +84,7 @@ const NetworkingView = lazy(() => import('./networking/NetworkingView').then(m =
|
||||
const GlobalObservabilityView = lazy(() => import('./GlobalObservabilityView').then(m => ({ default: m.GlobalObservabilityView })));
|
||||
|
||||
export default function EditorLayout() {
|
||||
const { isAdmin, can, permissions } = useAuth();
|
||||
const { isAdmin, can, permissions, permissionsStatus } = useAuth();
|
||||
const { status: trivy } = useTrivyStatus();
|
||||
const { runWithLog, panelState, logRows, healthGate } = useDeployFeedback();
|
||||
|
||||
@@ -837,12 +837,14 @@ export default function EditorLayout() {
|
||||
}
|
||||
}, [permissions, can]);
|
||||
|
||||
const createStackSlot = can('stack:create') ? (
|
||||
const canCreateStack = can('stack:create');
|
||||
const createStackSlot = (canCreateStack || permissionsStatus === 'loading') ? (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="rounded-lg w-full"
|
||||
onClick={() => openCreateDialog('empty')}
|
||||
disabled={!canCreateStack}
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Create Stack
|
||||
@@ -904,7 +906,7 @@ export default function EditorLayout() {
|
||||
createStackSlot={createStackSlot}
|
||||
onScan={handleScanStacks}
|
||||
isScanning={isScanning}
|
||||
canCreate={can('stack:create')}
|
||||
canCreate={canCreateStack}
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
filterChip={filterChip}
|
||||
@@ -935,10 +937,10 @@ export default function EditorLayout() {
|
||||
if (node) void stackActions.loadFileOnNode(node, file);
|
||||
},
|
||||
filterChip,
|
||||
onOpenCreate: can('stack:create') ? () => openCreateDialog('empty') : undefined,
|
||||
onOpenCreate: canCreateStack ? () => openCreateDialog('empty') : undefined,
|
||||
onOpenAdopt: can('stack:read') ? openAdoptDialog : undefined,
|
||||
onScan: handleScanStacks,
|
||||
canCreate: can('stack:create'),
|
||||
canCreate: canCreateStack,
|
||||
activeNodeId: activeNode?.id ?? null,
|
||||
openMuteRulesWithPrefill,
|
||||
stacksLoadStatus,
|
||||
|
||||
@@ -149,7 +149,7 @@ export function ViewRouter({
|
||||
isFileLoading,
|
||||
quickLinkCandidates,
|
||||
}: ViewRouterProps): ReactNode {
|
||||
const { can } = useAuth();
|
||||
const { can, permissionsStatus } = useAuth();
|
||||
const { isPaid, licenseReady } = useLicense();
|
||||
const { activeNode, activeNodeMeta } = useNodes();
|
||||
if (activeView === 'settings') {
|
||||
@@ -192,6 +192,7 @@ export function ViewRouter({
|
||||
// remote meta; null activeNode must not be treated as local (wrong-node
|
||||
// or doomed WebSocket). Stack deep links hydrate selectedFile async:
|
||||
// wait so we never open a compose-root shell, then reconnect into the stack.
|
||||
if (permissionsStatus === 'loading') return <ViewSkeleton />;
|
||||
if (!can('system:console')) return null;
|
||||
if (urlHydratingStack != null || (isHostConsoleStackDeepLink() && !selectedFile)) {
|
||||
return <ViewSkeleton />;
|
||||
|
||||
@@ -18,7 +18,7 @@ interface SectionGateProps {
|
||||
* guards remain the authoritative enforcement.
|
||||
*/
|
||||
export function SectionGate({ sectionId, children }: SectionGateProps) {
|
||||
const { isAdmin } = useAuth();
|
||||
const { isAdmin, permissionsStatus } = useAuth();
|
||||
const { isPaid } = useLicense();
|
||||
const { activeNode } = useNodes();
|
||||
|
||||
@@ -32,6 +32,10 @@ export function SectionGate({ sectionId, children }: SectionGateProps) {
|
||||
|
||||
const item = getSettingsItem(sectionId);
|
||||
|
||||
if (permissionsStatus === 'loading') {
|
||||
return <div className="h-48 animate-pulse rounded-lg bg-card" aria-busy="true" />;
|
||||
}
|
||||
|
||||
if (!item || !isItemVisible(item, visibility)) return null;
|
||||
if (isItemLocked(item, visibility)) return null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user