diff --git a/client/components/Breadcrumb/Breadcrumb.module.scss b/client/components/Breadcrumb/Breadcrumb.module.scss new file mode 100644 index 000000000..95cd99e4a --- /dev/null +++ b/client/components/Breadcrumb/Breadcrumb.module.scss @@ -0,0 +1,3 @@ +.breadcrumb { + margin-left: -10px; +} \ No newline at end of file diff --git a/client/components/Breadcrumb/Breadcrumb.tsx b/client/components/Breadcrumb/Breadcrumb.tsx index 75a021c6e..50d77c0c8 100644 --- a/client/components/Breadcrumb/Breadcrumb.tsx +++ b/client/components/Breadcrumb/Breadcrumb.tsx @@ -3,12 +3,16 @@ import { ReusableComponent } from 'components/types' import React from 'react' import { renderBreadcrumbItem } from './renderBreadcrumbItem' import { IBreadcrumbComponentProps } from './types' +import styles from './Breadcrumb.module.scss' +import { mergeClasses } from '@fluentui/react-components' export const BreadcrumbComponent: ReusableComponent< IBreadcrumbComponentProps > = (props) => { return ( - <div className={props.className}> + <div + className={mergeClasses(BreadcrumbComponent.className, props.className)} + > <Breadcrumb size='large'> {props.items.map((item) => renderBreadcrumbItem(item, props.items))} </Breadcrumb> @@ -17,6 +21,7 @@ export const BreadcrumbComponent: ReusableComponent< } BreadcrumbComponent.displayName = 'Breadcrumb' +BreadcrumbComponent.className = styles.breadcrumb BreadcrumbComponent.defaultProps = { items: [] } diff --git a/client/components/List/reducer.ts b/client/components/List/reducer.ts index 00ed7524f..59df7135d 100644 --- a/client/components/List/reducer.ts +++ b/client/components/List/reducer.ts @@ -45,12 +45,12 @@ function applyFilters<T = any>( (item) => _.filter(Object.keys(filterValues), (key) => { const value = get(item as any, key, '') - switch (typeof value) { + switch (typeof filterValues[key]) { case 'boolean': { return filterValues[key] === value } default: { - return filterValues[key].includes(value) + return filterValues[key]?.includes(value) } } }).length === Object.keys(filterValues).length diff --git a/client/graphql-queries/user/user-context.gql b/client/graphql-queries/user/user-context.gql index db99fa3f4..b23c16392 100644 --- a/client/graphql-queries/user/user-context.gql +++ b/client/graphql-queries/user/user-context.gql @@ -37,6 +37,8 @@ query UserContext { security { securityGroupEnabled securityGroupId + domainRestrictionEnabled + domainRestriction } } } diff --git a/client/i18n/en-GB.json b/client/i18n/en-GB.json index 2c233349d..a112774c9 100644 --- a/client/i18n/en-GB.json +++ b/client/i18n/en-GB.json @@ -217,7 +217,7 @@ "bulkImportUsersLabel": "Bulk import", "bulkImportingUsersLabel": "Importing {{count}} users. Please wait..", "addNewUser": "Add new", - "userFieldAdSync": "The field is automatically synchronized from Azure AD when the user logs in, and can not be modified in Did.", + "userFieldAdSync": "The field is automatically synchronized from Entra ID when the user logs in, and can not be modified in Did.", "syncUsersLabel": "Synchronize user properties", "synchronizingUserProperties": "Synchronizing user properties...", "updateSuccess": "Successfully updated user **{{displayName}}**.", @@ -226,8 +226,8 @@ "createError": "An error occured when attempting to create user **{{displayName}}**.", "addNewUserPanelTitle": "Add new user", "editUserPanelTitle": "Edit user", - "addNewUserPanelDescription": "Select a user from Azure Active Directory, set a role, and any changed properties that are not automatically synchronized.", - "editUserPanelDescription": "Change role or edit properties that are not automatically synced from Azure Active Directory. You can also hide the user from overviews.", + "addNewUserPanelDescription": "Select a user from Entra ID, set a role, and any changed properties that are not automatically synchronized.", + "editUserPanelDescription": "Change role or edit properties that are not automatically synced from Entra ID. You can also hide the user from overviews.", "employmentStartDateLabel": "Employment Start Date", "employmentEndDateLabel": "Employment End Date", "employmentEndDateDescription": "The date the user's employment ends. If the user is no longer employed, set this date to the last day of employment.", @@ -259,15 +259,15 @@ "forecastNotificationsDescription": "How many weeks ahead should users forecast.", "forecastNotificationsLabel": "Notifications", "summaryRangeValueFormat": "Showing {{value}} months", - "adsync": "Azure AD Sync", + "adsync": "Entra ID Sync", "adUserSyncEnabledLabel": "Synchronize user properties", - "adUserSyncEnabledDescription": "Automatically synchronize user properties from Azure Active Directory when the user logs in.", + "adUserSyncEnabledDescription": "Automatically synchronize user properties from Entra ID when the user logs in.", "adUserSyncPropertiesLabel": "Properties to synchronize", - "adUserSyncPropertiesDescription": "Choose which properties that should be automatically synchronized from Azure Active Directory.", + "adUserSyncPropertiesDescription": "Choose which properties that should be automatically synchronized from Entra ID.", "roleInUseMessage": "This role is assigned to {{count}} user(s) and cannot be deleted. ", "userHiddenFromReportsLabel": "Hidden from reports", "adUserSyncUserPhotoLabel": "Synchronize user photo", - "adUserSyncUserPhotoDescription": "Synchronize user photo from Azure Active Directory when the users logs in.", + "adUserSyncUserPhotoDescription": "Synchronize user photo from Entra ID when the users logs in.", "subscriptionInfoHeader": "Basic info", "vacation": "Holidays and absence", "vacationTotalDaysLabel": "Vacation days", @@ -339,10 +339,14 @@ "budgetTrackingEnabledLabel": "Enable Budget Tracking", "budgetTrackingEnabledDescription": "Enabling this setting will enable additional properties on the projects making it possible to visualize how many hours are registered for the project and how it's going. This feature will provide users with a simple overview of project progress", "security": "Security", - "securityGroupIdLabel": "Azure Entra ID Security Group ID", - "securityGroupIdDescription": "The ID of the Azure AD security group that should have access to the application. If the field is empty, users with access needs to be manually added to the application.", - "securityGroupEnabledLabel": "Enable Azure Entra ID Security Group Access", - "securityGroupEnabledDescription": "Enable access to the application for users in the specified Azure AD security group." + "securityGroupIdLabel": "Entra ID Security Group ID", + "securityGroupIdDescription": "The ID of the Entra ID security group that should have access to the application. If the field is empty, users with access needs to be manually added to the application.", + "securityGroupEnabledLabel": "Enable Entra ID Security Group Access", + "securityGroupEnabledDescription": "Enable access to the application for users in the specified Entra ID security group.", + "domainRestrictionEnabledLabel": "Enable domain restriction", + "domainRestrictionEnabledDescription": "In addition to the Entra ID security group, you can restrict access to the application to users in the specified domain.", + "domainRestrictionLabel": "Restrict access to users in the following domain", + "domainRestrictionDescription": "In addition to the Entra ID security group, you can restrict access to the application to users in the specified domain. If the field is empty, all users in the Entra ID security group will have access to the application." }, "reports": { "generatingReportProgressText": "Please wait while we generate the report for you...", @@ -614,7 +618,7 @@ "startPageLabel": "Start page", "preferredLanguageDescription": "Did will display menus and buttons in this language.", "googleSignInText": "Sign in with Google", - "activeDirectory": "Azure AD", + "activeDirectory": "Entra ID", "google": "Google", "signInDisabledText": "Sign in is currently disabled. Please hold on.", "error": "Error", @@ -715,7 +719,7 @@ "manageReportLinksDescription": "Manage report links. Add, edit and delete report links.", "selectAll": "Select/deselect all", "importUsers": "Retrieve users from AD", - "importUsersDescription": "Retrieve users from Azure Active Directory and register them in the system. This is not something that everyone should have access to.", + "importUsersDescription": "Retrieve users from Entra ID and register them in the system. This is not something that everyone should have access to.", "manageApiTokensDescription": "Manage (create new, delete existing, and view existing keys) API keys. It is good to be careful about who gets this access, as there is quite a lot that can be done with this much power.", "manageApiTokens": "Manage API-tokens", "listApiTokens": "List API-tokens", diff --git a/client/i18n/nb.json b/client/i18n/nb.json index 72db5d8da..2460275b9 100644 --- a/client/i18n/nb.json +++ b/client/i18n/nb.json @@ -186,19 +186,19 @@ "bulkImportUsersLabel": "Importer i bulk", "bulkImportingUsersLabel": "Importerer {{count}} brukere. Vennligst vent...", "addNewUser": "Legg til ny", - "userFieldAdSync": "Feltet synkroniseres automatisk fra Azure AD når brukeren logger på, og kan ikke endres i Did.", + "userFieldAdSync": "Feltet synkroniseres automatisk fra Entra ID når brukeren logger på, og kan ikke endres i Did.", "syncUsersLabel": "Synkroniser brukeregenskaper", "synchronizingUserProperties": "Synkroniserer brukeregenskaper...", "updateSuccess": "Brukeren **{{displayName}}** ble oppdatert uten problem.", "createSuccess": "Brukeren **{{displayName}}** er opprettet og er nå klar til å begynne å registrere timer.", "updateError": "Det oppstod en feil under oppdatering av bruker **{{displayName}}**.", "createError": "Det oppstod en feil under opprettelse av bruker **{{displayName}}**.", - "editUserPanelDescription": "Endre rolle eller rediger egenskaper som ikke automatisk blir synkronisert fra Azure Active Directory. Du kan også skjule brukeren fra timeoversikter.", - "addNewUserPanelDescription": "Velg en bruker fra Azure Active Directory, sett en rolle, og eventuelt endre på egenskaper som ikke sykroniseres automatisk.", + "editUserPanelDescription": "Endre rolle eller rediger egenskaper som ikke automatisk blir synkronisert fra Entra ID. Du kan også skjule brukeren fra timeoversikter.", + "addNewUserPanelDescription": "Velg en bruker fra Entra ID, sett en rolle, og eventuelt endre på egenskaper som ikke sykroniseres automatisk.", "addNewUserPanelTitle": "Legg til ny bruker", "editUserPanelTitle": "Rediger bruker", - "employmentEndDateDescription": "Datoen brukerens arbeidsforhold avsluttes. \nDersom brukeren ikke lenger er ansatt, sett denne datoen til siste arbeidsdag.", - "employmentStartDateDescription": "Datoen brukerens ansettelse starter. \nHvis brukeren allerede er ansatt, sett denne datoen til første arbeidsdag.", + "employmentEndDateDescription": "Datoen brukerens arbeidsforhold avsluttes. Dersom brukeren ikke lenger er ansatt, sett denne datoen til siste arbeidsdag.", + "employmentStartDateDescription": "Datoen brukerens ansettelse starter. Hvis brukeren allerede er ansatt, sett denne datoen til første arbeidsdag.", "employmentEndDateLabel": "Sluttdato for ansettelse", "employmentStartDateLabel": "Startdato for ansettelse" }, @@ -296,15 +296,15 @@ "forecastNotificationsDescription": "Hvor mange uker fram i tid skal brukerne prognosere?", "forecastNotificationsLabel": "Varsler", "summaryRangeValueFormat": "Viser {{value}} måneder", - "adsync": "Synkronisering med Azure AD", + "adsync": "Synkronisering med Entra ID", "adUserSyncEnabledLabel": "Synkroniser brukeregenskaper", - "adUserSyncEnabledDescription": "Synkroniser automatisk brukeregenskaper fra Azure Active Directory når brukeren logger på.", + "adUserSyncEnabledDescription": "Synkroniser automatisk brukeregenskaper fra Entra ID når brukeren logger på.", "adUserSyncPropertiesLabel": "Egenskaper som skal synkroniseres", - "adUserSyncPropertiesDescription": "Velg hvilke egenskaper som skal synkroniseres automatisk fra Azure Active Directory.", + "adUserSyncPropertiesDescription": "Velg hvilke egenskaper som skal synkroniseres automatisk fra Entra ID.", "roleInUseMessage": "Denne rollen er tildelt {{count}} brukere og kan ikke slettes.", "userHiddenFromReportsLabel": "Skjult fra timeoversikt", "adUserSyncUserPhotoLabel": "Synkroniser profilbilde", - "adUserSyncUserPhotoDescription": "Synkroniser profilbilde fra Azure Active Directory når brukerne logger på.", + "adUserSyncUserPhotoDescription": "Synkroniser profilbilde fra Entra ID når brukerne logger på.", "subscriptionInfoHeader": "Grunnleggende informasjon", "vacationEventCategoryLabel": "Kalenderoppføringskategori i Outlook", "vacationEventCategoryDescription": "Kategori som skal brukes til å merke kalenderoppføringer i Outlook som ferie.", @@ -337,10 +337,14 @@ "budgetTracking": "Budsjettoppfølging", "budgetTrackingEnabledLabel": "Aktiver budsjettoppfølging", "security": "Sikkerhet", - "securityGroupIdLabel": "Azure Entra ID Sikkerhetsgruppe ID", - "securityGroupIdDescription": "ID-en til Azure AD-sikkerhetsgruppen som skal ha tilgang til applikasjonen. Hvis feltet er tomt, må brukere med tilgang legges til manuelt i applikasjonen.", - "securityGroupEnabledLabel": "Aktiver tilgang gjennom en sikkerhetsgruppe i Azure Entra ID.", - "securityGroupEnabledDescription": "Aktiver tilgang til applikasjonen for brukere i den angitte Azure AD-sikkerhetsgruppen." + "securityGroupIdLabel": "Entra ID Sikkerhetsgruppe ID", + "securityGroupIdDescription": "ID-en til Entra ID-sikkerhetsgruppen som skal ha tilgang til applikasjonen. Hvis feltet er tomt, må brukere med tilgang legges til manuelt i applikasjonen.", + "securityGroupEnabledLabel": "Aktiver tilgang gjennom en sikkerhetsgruppe i Entra ID.", + "securityGroupEnabledDescription": "Aktiver tilgang til applikasjonen for brukere i den angitte Entra ID-sikkerhetsgruppen.", + "domainRestrictionLabel": "Begrens tilgang til brukere i følgende domene", + "domainRestrictionDescription": "I tillegg til Entra ID-sikkerhetsgruppen kan du begrense tilgangen til applikasjonen til brukere i det angitte domenet. Hvis feltet er tomt, vil alle brukere i Entra ID-sikkerhetsgruppen ha tilgang til applikasjonen.", + "domainRestrictionEnabledLabel": "Aktiver domenebegrensning", + "domainRestrictionEnabledDescription": "I tillegg til Entra ID-sikkerhetsgruppen kan du begrense tilgangen til applikasjonen til brukere i det angitte domenet." }, "reports": { "generatingReportProgressText": "Vennligst vent mens vi genererer rapporten for deg...", @@ -612,7 +616,7 @@ "startPageLabel": "Startside", "preferredLanguageDescription": "Did viser menyer og knapper på dette språket.", "googleSignInText": "Logg på med Google", - "activeDirectory": "Azure AD", + "activeDirectory": "Entra ID", "google": "Google", "signInDisabledText": "Pålogging er for øyeblikket deaktivert. \nVennligst vent.", "error": "Feilmelding", @@ -712,7 +716,7 @@ "category_api": "API", "selectAll": "Velg/fjern alle", "importUsers": "Hent brukere fra AD", - "importUsersDescription": "Hente ut brukere fra Azure Active Directory og registere de i systemet. Dette er ikke noe alle burde ha tilgang til.", + "importUsersDescription": "Hente ut brukere fra Entra ID og registere de i systemet. Dette er ikke noe alle burde ha tilgang til.", "manageApiTokensDescription": "Administere (opprette nye, slette eksisterende, og se eksisterende nøkler) API-nøkler. Det er greit å være forsiktig med hvem som får denne tilgangen, da det er ganske mye som kan gjøres med så mye krefter.", "manageApiTokens": "Administrere API-nøkler", "listApiTokensDescription": "Se eksisterende API-nøkler. Du har kun tilgang til grunnleggende informasjon om nøklene. Navn, beskrivelse, opprettet dato og når de utløper. Du har ikke mulighet for å hente ut selve nøkkelen som trengs for å kjøre spørringen fra tredjeapartssystemer.", diff --git a/client/i18n/nn.json b/client/i18n/nn.json index 16884f8e9..0522bb701 100644 --- a/client/i18n/nn.json +++ b/client/i18n/nn.json @@ -189,7 +189,7 @@ "bulkImportUsersLabel": "Importer i bulk", "bulkImportingUsersLabel": "Importerer {{count}} brukarar. Ver vennleg å vent...", "addNewUser": "Legg til ny", - "userFieldAdSync": "Feltet blir synkronisert automatisk frå Azure AD når brukaren loggar seg på, og kan ikkje endrast i Did.", + "userFieldAdSync": "Feltet blir synkronisert automatisk frå Entra ID når brukaren loggar seg på, og kan ikkje endrast i Did.", "syncUsersLabel": "Synkroniser brukeregenskaper", "synchronizingUserProperties": "Synkroniserer brukaregenskaper...", "updateSuccess": "Brukaren **{{displayName}}** vart oppdatert utan problem.", @@ -198,8 +198,8 @@ "createError": "Det oppstod ein feil under oppretting av brukar **{{displayName}}**.", "editUserPanelTitle": "Rediger brukar", "addNewUserPanelTitle": "Legg til ny brukar", - "editUserPanelDescription": "Endre rolle eller rediger eigenskapar som ikkje automatisk blir synkronisert frå Azure Active Directory. Du kan også skjula brukaren frå timeoversikter.", - "addNewUserPanelDescription": "Velg en bruker fra Azure Active Directory, sett en rolle, og eventuelt endre på egenskaper som ikke sykroniseres automatisk.", + "editUserPanelDescription": "Endre rolle eller rediger eigenskapar som ikkje automatisk blir synkronisert frå Entra ID. Du kan også skjula brukaren frå timeoversikter.", + "addNewUserPanelDescription": "Velg en bruker fra Entra ID, sett en rolle, og eventuelt endre på egenskaper som ikke sykroniseres automatisk.", "employmentEndDateDescription": "Datoen brukerens arbeidsforhold avsluttes. \nDersom brukeren ikke lenger er ansatt, sett denne datoen til siste arbeidsdag.", "employmentStartDateDescription": "Datoen brukerens ansettelse starter. \nHvis brukeren allerede er ansatt, sett denne datoen til første arbeidsdag.", "employmentEndDateLabel": "Sluttdato for ansettelse", @@ -298,15 +298,15 @@ "forecastNotificationsDescription": "Kor mange veker fram i tid skal brukarane prognosere?", "forecastNotificationsLabel": "Varsel", "summaryRangeValueFormat": "Viser {{value}} månader", - "adsync": "Synkronisering med Azure AD", + "adsync": "Synkronisering med Entra ID", "adUserSyncEnabledLabel": "Synkroniser brukareigenskapar", - "adUserSyncEnabledDescription": "Synkroniser automatisk brukareigenskapar frå Azure Active Directory når brukaren loggar på.", + "adUserSyncEnabledDescription": "Synkroniser automatisk brukareigenskapar frå Entra ID når brukaren loggar på.", "adUserSyncPropertiesLabel": "Eigenskapar som skal synkroniserast", - "adUserSyncPropertiesDescription": "Vel kva eigenskapar som skal synkroniserast automatisk frå Azure Active Directory.", + "adUserSyncPropertiesDescription": "Vel kva eigenskapar som skal synkroniserast automatisk frå Entra ID.", "roleInUseMessage": "Denne rolla er tildelt {{count}} brukar(ar) og kan ikkje slettast.", "userHiddenFromReportsLabel": "Skjult frå timeoversikt", "adUserSyncUserPhotoLabel": "Synkroniser profilbilete", - "adUserSyncUserPhotoDescription": "Synkroniser profilbilete frå Azure Active Directory når brukarane loggar seg på.", + "adUserSyncUserPhotoDescription": "Synkroniser profilbilete frå Entra ID når brukarane loggar seg på.", "subscriptionInfoHeader": "Grunnleggjande informasjon", "vacationEventCategoryLabel": "Hendelseskategori i Outlook", "vacationTotalDaysDescription": "Det samla talet feriedagar for kvar tilsett i selskapet.", @@ -338,10 +338,14 @@ "budgetTracking": "Budsjettoppfølging", "budgetTrackingEnabledLabel": "Aktiver budsjettoppfølging", "security": "Sikkerhet", - "securityGroupIdLabel": "Azure Entra ID Sikkerhetsgruppe ID", - "securityGroupIdDescription": "ID-en til Azure AD-sikkerhetsgruppen som skal ha tilgang til applikasjonen. Hvis feltet er tomt, må brukere med tilgang legges til manuelt i applikasjonen.@", - "securityGroupEnabledLabel": "Aktiver tilgang gjennom en sikkerhetsgruppe i Azure Entra ID.", - "securityGroupEnabledDescription": "Aktiver tilgang til applikasjonen for brukere i den angitte Azure AD-sikkerhetsgruppen." + "securityGroupIdLabel": "Entra ID Sikkerhetsgruppe ID", + "securityGroupIdDescription": "ID-en til Entra ID-sikkerhetsgruppen som skal ha tilgang til applikasjonen. Hvis feltet er tomt, må brukere med tilgang legges til manuelt i applikasjonen.@", + "securityGroupEnabledLabel": "Aktiver tilgang gjennom en sikkerhetsgruppe i Entra ID.", + "securityGroupEnabledDescription": "Aktiver tilgang til applikasjonen for brukere i den angitte Entra ID-sikkerhetsgruppen.", + "domainRestrictionLabel": "Begrens tilgang til brukere i følgende domene", + "domainRestrictionDescription": "I tillegg til Entra ID-sikkerhetsgruppen kan du begrense tilgangen til applikasjonen til brukere i det angitte domenet. Hvis feltet er tomt, vil alle brukere i Entra ID-sikkerhetsgruppen ha tilgang til applikasjonen.", + "domainRestrictionEnabledLabel": "Aktiver domenebegrensning", + "domainRestrictionEnabledDescription": "I tillegg til Entra ID-sikkerhetsgruppen kan du begrense tilgangen til applikasjonen til brukere i det angitte domenet." }, "reports": { "generatingReportProgressText": "Vennligst vent mens vi genererer rapporten for deg...", @@ -613,7 +617,7 @@ "startPageLabel": "Startside", "preferredLanguageDescription": "Did viser menyar og knappar på dette språket.", "googleSignInText": "Logg på med Google", - "activeDirectory": "Azure AD", + "activeDirectory": "Entra ID", "google": "Google", "signInDisabledText": "Pålogging er for øyeblikket deaktivert. \nVennligst vent.", "error": "Feilmelding", @@ -713,7 +717,7 @@ "category_api": "API", "selectAll": "Velg/fjern alle", "importUsers": "Hent brukere fra AD", - "importUsersDescription": "Hente ut brukere fra Azure Active Directory og registere de i systemet. Dette er ikke noe alle burde ha tilgang til.", + "importUsersDescription": "Hente ut brukere fra Entra ID og registere de i systemet. Dette er ikke noe alle burde ha tilgang til.", "manageApiTokens": "Administrere API-nøkler", "manageApiTokensDescription": "Administere (opprette nye, slette eksisterende, og se eksisterende nøkler) API-nøkler. Det er greit å være forsiktig med hvem som får denne tilgangen, da det er ganske mye som kan gjøres med så mye krefter.", "listApiTokens": "Liste ut API-nøkler", diff --git a/client/pages/Admin/SubscriptionSettings/useSubscriptionConfig.ts b/client/pages/Admin/SubscriptionSettings/useSubscriptionConfig.ts index 8437aa273..8f8aa3a9b 100644 --- a/client/pages/Admin/SubscriptionSettings/useSubscriptionConfig.ts +++ b/client/pages/Admin/SubscriptionSettings/useSubscriptionConfig.ts @@ -1,12 +1,12 @@ +import { useTheme } from '@fluentui/react' import { CheckboxProps, SliderProps } from '@fluentui/react-components' import { useAppContext } from 'AppContext' import { DateObject } from 'DateUtils' +import _ from 'lodash' import { useTranslation } from 'react-i18next' import { SubscriptionSettings } from 'types' import { ISettingsSectionProps } from './SettingsSection/types' import { SubscriptionSettingField } from './types' -import { useTheme } from '@fluentui/react' -import _ from 'lodash' /** * Component logic for `SubscriptionSettings` component. Handles the @@ -92,6 +92,29 @@ export function useSubscriptionConfig() { label: t('admin.securityGroupIdLabel'), description: t('admin.securityGroupIdDescription') } + }, + { + id: 'domainRestrictionEnabled', + type: 'bool', + disabledIf: (settings: SubscriptionSettings) => + !_.get(settings, 'security.securityGroupEnabled'), + props: { + label: t('admin.domainRestrictionEnabledLabel'), + description: t('admin.domainRestrictionEnabledDescription') + } + }, + { + id: 'domainRestriction', + type: 'text', + disabledIf: (settings: SubscriptionSettings) => + !_.get(settings, 'security.securityGroupEnabled'), + hiddenIf: (settings: SubscriptionSettings) => + !_.get(settings, 'security.domainRestrictionEnabled'), + props: { + label: t('admin.domainRestrictionLabel'), + description: t('admin.domainRestrictionDescription'), + contentBefore: '@' + } } ] }, diff --git a/client/pages/Projects/ProjectList/ProjectList.tsx b/client/pages/Projects/ProjectList/ProjectList.tsx index b71583ab5..4b76452bc 100644 --- a/client/pages/Projects/ProjectList/ProjectList.tsx +++ b/client/pages/Projects/ProjectList/ProjectList.tsx @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next' import { useProjectsContext } from '../context' import { IProjectListProps } from './types' import { useProjectList } from './useProjectList' +import { ListMenuItem } from 'components/List/ListToolbar' /** * Project list component used by `<Projects />`. Renders @@ -15,25 +16,34 @@ import { useProjectList } from './useProjectList' export const ProjectList: TabComponent<IProjectListProps> = (props) => { const { t } = useTranslation() const context = useProjectsContext() - const { projects, inactiveProjects, columns, showInactive, getKey } = - useProjectList(props) + const { columns, showInactive, getKey } = useProjectList(props) return ( <> <List {...props} enableShimmer={context.loading} - items={projects} + items={context.state?.projects ?? []} columns={columns} groups={props.groups} getKey={getKey} - menuItems={[ - inactiveProjects.length > 0 && + menuItems={(_context) => [ + (context.state?.projects ?? []).some((c) => c.inactive) && InactiveCheckboxMenuItem( - t('projects.toggleInactive', { count: inactiveProjects.length }), + t('projects.toggleInactive', { + count: _context.state.itemsPreFilter.filter((c) => c.inactive) + .length + }), showInactive.toggle ), - ...props.menuItems + ...(props.menuItems as ListMenuItem[]) ]} + filterValues={ + showInactive.value + ? {} + : { + inactive: false + } + } /> {props.children} </> diff --git a/client/pages/Projects/ProjectList/useProjectList.ts b/client/pages/Projects/ProjectList/useProjectList.ts index 38306266b..98815c09b 100644 --- a/client/pages/Projects/ProjectList/useProjectList.ts +++ b/client/pages/Projects/ProjectList/useProjectList.ts @@ -1,8 +1,6 @@ /* eslint-disable unicorn/consistent-function-scoping */ -import { useEffect, useMemo, useState } from 'react' import { Project } from 'types' import { useBoolean } from 'usehooks-ts' -import { useProjectsContext } from '../context' import { IProjectListProps } from './types' import { useColumns } from './useColumns' @@ -18,37 +16,14 @@ import { useColumns } from './useColumns' * @category Projects */ export function useProjectList(props: IProjectListProps) { - const context = useProjectsContext() - const initialProjects = useMemo(() => { - let projects = context?.state?.projects ?? props.items - if (props.id === 'm') { - projects = projects.filter(({ outlookCategory }) => !!outlookCategory) - } - return projects - }, [context?.state?.projects, props.items, props.id]) - const [projects, setProjects] = useState(initialProjects) const showInactive = useBoolean(false) const columns = useColumns(props) - useEffect( - () => - setProjects( - [...initialProjects].filter( - ({ inactive }) => showInactive.value || !inactive - ) - ), - [initialProjects, props.id, showInactive.value] - ) - - const inactiveProjects = initialProjects.filter(({ inactive }) => inactive) - function getKey(project: Project, index: number) { return `project_list_item_${project?.tag ?? index}` } return { - projects, - inactiveProjects, columns, showInactive, getKey diff --git a/package-lock.json b/package-lock.json index ecf29fe2a..016eda55e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "did", - "version": "0.13.3-7", + "version": "0.13.3-8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "did", - "version": "0.13.3-7", + "version": "0.13.3-8", "dependencies": { "@apollo/client": "3.8.5", "@apollo/server": "4.9.4", diff --git a/package.json b/package.json index 7f5144b4a..e8f4e7e19 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "did", "description": "the calendar is your timesheet", - "version": "0.13.3-7", + "version": "0.13.3-8", "private": true, "repository": { "url": "https://github.com/Puzzlepart/did" diff --git a/server/graphql/resolvers/subscription/types/SubscriptionSecuritySettings.ts b/server/graphql/resolvers/subscription/types/SubscriptionSecuritySettings.ts index cdbea42ba..dae57965c 100644 --- a/server/graphql/resolvers/subscription/types/SubscriptionSecuritySettings.ts +++ b/server/graphql/resolvers/subscription/types/SubscriptionSecuritySettings.ts @@ -23,6 +23,12 @@ export class SubscriptionSecuritySettings { defaultValue: '00000000-0000-0000-0000-000000000000' }) securityGroupId?: string + + @Field({ nullable: true }) + domainRestrictionEnabled?: boolean + + @Field({ nullable: true }) + domainRestriction?: string } /** @@ -45,4 +51,10 @@ export class SubscriptionSecuritySettingsInput { defaultValue: '00000000-0000-0000-0000-000000000000' }) securityGroupId?: string + + @Field({ nullable: true }) + domainRestrictionEnabled?: boolean + + @Field({ nullable: true }) + domainRestriction?: string } diff --git a/server/middleware/passport/microsoft/checkSecurityGroupMembership.ts b/server/middleware/passport/microsoft/checkSecurityGroupMembership.ts index c0e50e791..9ef6db413 100644 --- a/server/middleware/passport/microsoft/checkSecurityGroupMembership.ts +++ b/server/middleware/passport/microsoft/checkSecurityGroupMembership.ts @@ -1,29 +1,29 @@ +import { SubscriptionSecuritySettings } from '../../../graphql/resolvers/subscription/types/SubscriptionSecuritySettings' import { MSGraphService, MSOAuthService } from '../../../services' -import { Subscription } from '../../../graphql/resolvers/types' /** * Checks if a user is a member of the security group defined * in the subscription settings. * - * @param subscription The subscription object. + * @param settings The subscription security settings. * @param tokenParameters The token parameters. * @param mail The email of the user. * * @returns A boolean indicating whether the user is a member of the security group. */ export const checkSecurityGroupMembership = async ( - subscription: Subscription, + settings: SubscriptionSecuritySettings, tokenParameters: any, mail: string ) => { if ( - !subscription.settings?.security?.securityGroupEnabled || - !subscription.settings?.security?.securityGroupId + !settings.securityGroupEnabled || + !settings.securityGroupId || + !mail.includes(`@${settings.domainRestriction}`) ) return false const msAuthSvc = new MSOAuthService({ user: { - subscription, tokenParams: tokenParameters } }) @@ -31,7 +31,7 @@ export const checkSecurityGroupMembership = async ( const msGraphSvc = new MSGraphService(msAuthSvc) return await msGraphSvc.isUserMemberOfSecurityGroup( - subscription.settings?.security?.securityGroupId, + settings.securityGroupId, mail ) } diff --git a/server/middleware/passport/microsoft/onVerifySignin.ts b/server/middleware/passport/microsoft/onVerifySignin.ts index 80e36168e..14cec3a6a 100644 --- a/server/middleware/passport/microsoft/onVerifySignin.ts +++ b/server/middleware/passport/microsoft/onVerifySignin.ts @@ -56,7 +56,7 @@ export const onVerifySignin = async ( if (!dbUser && !isOwner) { isUserInSecurityGroup = await checkSecurityGroupMembership( - subscription, + subscription?.settings?.security ?? {}, tokenParameters, mail )