diff --git a/frontend/src/HomePage/HomePage.jsx b/frontend/src/HomePage/HomePage.jsx index 0e40e0078c..2b9586029a 100644 --- a/frontend/src/HomePage/HomePage.jsx +++ b/frontend/src/HomePage/HomePage.jsx @@ -47,6 +47,7 @@ import { ConsultationBanner, } from '@/modules/dashboard/components'; import CreateAppWithPrompt from '@/modules/AiBuilder/components/CreateAppWithPrompt'; +import SolidIcon from '@/_ui/Icon/SolidIcons'; const { iconList, defaultIcon } = configs; @@ -118,6 +119,7 @@ class HomePageComponent extends React.Component { dependentPluginsDetail: {}, showMissingGroupsModal: false, missingGroups: [], + missingGroupsExpanded: false, }; } @@ -903,6 +905,7 @@ class HomePageComponent extends React.Component { dependentPluginsDetail, showMissingGroupsModal, missingGroups, + missingGroupsExpanded, } = this.state; const modalConfigs = { create: { @@ -954,6 +957,40 @@ class HomePageComponent extends React.Component { }; const isAdmin = authenticationService?.currentSessionValue?.admin; const isBuilder = authenticationService?.currentSessionValue?.is_builder; + + const testGroups = [ + { name: 'Group 1' }, + { name: 'Group 2 long name' }, + { name: 'Group 3 med' }, + { name: 'Group 4 med' }, + { name: 'Group 4 really long name' }, + { name: 'Group 1' }, + { name: 'Group 2 long name' }, + { name: 'Group 3 med' }, + { name: 'Group 4 med' }, + { name: 'Group 4 really long name' }, + { name: 'Group 1' }, + { name: 'Group 2 long name' }, + { name: 'Group 3 med' }, + { name: 'Group 4 med' }, + { name: 'Group 4 really long name' }, + { name: 'Group 1' }, + { name: 'Group 2 long name' }, + { name: 'Group 3 med' }, + { name: 'Group 4 med' }, + { name: 'Group 4 really long name' }, + { name: 'Group 1' }, + { name: 'Group 2 long name' }, + { name: 'Group 3 med' }, + { name: 'Group 4 med' }, + { name: 'Group 4 really long name' }, + ]; + + //import app missing groups modal config + const threshold = 3; + const isLong = missingGroups.length > threshold; + const displayedGroups = missingGroupsExpanded ? missingGroups : missingGroups.slice(0, threshold); + return (
@@ -969,7 +1006,8 @@ class HomePageComponent extends React.Component { onCommitChange={this.handleCommitChange} /> this.importFile(fileContent, fileName, true)} show={showMissingGroupsModal} isLoading={importingApp} @@ -978,17 +1016,80 @@ class HomePageComponent extends React.Component { title: 'Import', tooltipMessage: '', }} + className="missing-groups-modal" darkMode={this.props.darkMode} > -

- The following group permissions are missing for page permissions. Are you sure you want to continue? -

-
- {missingGroups.map((item, index) => ( -
- {`${index + 1}. ${item}`} +
+
+ +
+
Warning: Missing user groups for permissions
+

+ Permissions for the following user group(s) won’t be applied since they do not exist in this + workspace. +

- ))} +
+ +
+
+
+ User groups +
+
+ {displayedGroups.map((group, idx) => ( + + {group} + {idx < displayedGroups.length - 1 ? ', ' : ''} + + ))} + {!missingGroupsExpanded && isLong && '...'} +
+
+ + {isLong && ( + + )} +
+ +

+ Restricted pages, queries, or components will become accessible to all users or to existing groups with + permissions. To avoid this, create the missing groups before importing, or reconfigure permissions after + import. +

+ +
+ this.setState({ showMissingGroupsModal: false, isImportingApp: false })} + > + Cancel import + + this.importFile(fileContent, fileName, true)} + className="primary-action" + > + Import with limited permissions + +
{showRenameAppModal && ( diff --git a/frontend/src/_styles/theme.scss b/frontend/src/_styles/theme.scss index e464a7b86f..50894aefbf 100644 --- a/frontend/src/_styles/theme.scss +++ b/frontend/src/_styles/theme.scss @@ -18875,4 +18875,70 @@ section.ai-message-prompt-input-wrapper { .cm-editor { max-height: 100px !important; } +} + +.missing-groups-modal { + .modal-body { + padding: 16px; + + .header { + padding-top: 12px; + padding-left: 4px; + font-weight: 500; + font-size: 14px; + } + + .sub-header { + margin-bottom: 0px; + font-size: 12px; + } + + .groups-list { + padding-top: 16px; + padding-bottom: 16px; + + .container { + padding: 12px; + } + } + + .info { + margin-bottom: 0px; + font-size: 12px; + padding-bottom: 24px; + } + + .action-btns { + justify-content: space-between; + } + + .primary-action, .secondary-action { + padding: 8px !important; + font-size: 12px; + } + + .toggle-button { + display: inline-flex; + align-items: center; + font-size: 14px; + color: var(--icon-brand); + background: none; + border: none; + cursor: pointer; + padding: 0; + font-family: inherit; + } + + .toggle-button:hover { + text-decoration: underline; + } + + .toggle-button .chevron { + transition: transform 0.2s ease; + } + + .toggle-button.expanded .chevron { + transform: rotate(180deg); + } + } } \ No newline at end of file diff --git a/frontend/src/_ui/Modal/index.jsx b/frontend/src/_ui/Modal/index.jsx index b9d48f0d88..6ed7fa04db 100644 --- a/frontend/src/_ui/Modal/index.jsx +++ b/frontend/src/_ui/Modal/index.jsx @@ -18,6 +18,8 @@ export default function ModalBase({ className = '', size = 'sm', headerAction, + showHeader = true, + showFooter = true, }) { return ( - - - {title} - -
- {headerAction && headerAction()} - -
-
+ {showHeader && ( + + + {title} + +
+ {headerAction && headerAction()} + +
+
+ )} {children ? ( children @@ -45,28 +49,30 @@ export default function ModalBase({
)} - - - Cancel - - -
- - {confirmBtnProps?.title || 'Continue'} - -
-
-
+ {showFooter && ( + + + Cancel + + +
+ + {confirmBtnProps?.title || 'Continue'} + +
+
+
+ )} ); }