Gate export/import command menu items by permission flag (#19991)

## Summary
- Hides the `exportRecords`, `exportView`, and `importRecords` command
menu actions from
users whose role does not hold the matching `EXPORT_CSV` / `IMPORT_CSV`
permission flag.
- Exposes the current user's role permission flags to
`conditionalAvailabilityExpression`
by adding `permissionFlags: Record<string, boolean>` to
`CommandMenuContextApi`, mirroring
 how `featureFlags` is already accessible.
- Adds a `2.1.0` workspace upgrade command that rewrites the three
existing rows on every
 active/suspended workspace.

## Before
<img width="1294" height="287" alt="Screenshot 2026-04-22 at 19 37 40"
src="https://github.com/user-attachments/assets/11ca8635-14d7-40a0-9ca0-76329c54e3c6"
/>

## After
<img width="1283" height="285" alt="Screenshot 2026-04-22 at 19 32 25"
src="https://github.com/user-attachments/assets/5e49fa8a-4541-42ee-96da-4c1de7d00aae"
/>
This commit is contained in:
Weiko
2026-04-24 17:22:44 +02:00
committed by GitHub
parent 6c1c0737b0
commit 2ccc293f99
11 changed files with 233 additions and 5 deletions
@@ -1,3 +1,4 @@
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector';
import { CommandMenuContext } from '@/command-menu-item/contexts/CommandMenuContext';
@@ -25,6 +26,7 @@ export const StandalonePageCommandMenu = () => {
const isMobile = useIsMobile();
const commandMenuItems = useAtomStateValue(commandMenuItemsSelector);
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
const currentUserWorkspace = useAtomStateValue(currentUserWorkspaceState);
const currentPageLayoutId = useAtomStateValue(currentPageLayoutIdState);
const isLayoutCustomizationModeEnabled = useAtomStateValue(
isLayoutCustomizationModeEnabledState,
@@ -38,6 +40,12 @@ export const StandalonePageCommandMenu = () => {
featureFlags[flag.key] = flag.value === true;
}
const permissionFlags: Record<string, boolean> = {};
for (const flag of currentUserWorkspace?.permissionFlags ?? []) {
permissionFlags[flag] = true;
}
const targetObjectReadPermissions: Record<string, boolean> = {};
const targetObjectWritePermissions: Record<string, boolean> = {};
@@ -74,6 +82,7 @@ export const StandalonePageCommandMenu = () => {
},
selectedRecords: [],
featureFlags,
permissionFlags,
targetObjectReadPermissions,
targetObjectWritePermissions,
objectMetadataItem: {},
@@ -81,6 +90,7 @@ export const StandalonePageCommandMenu = () => {
};
}, [
currentWorkspace?.featureFlags,
currentUserWorkspace?.permissionFlags,
isLayoutCustomizationModeEnabled,
objectMetadataItems,
store,