@strapi/admin 5.53.0 → 5.55.0
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/admin/admin/src/App.js +1 -1
- package/dist/admin/admin/src/App.js.map +1 -1
- package/dist/admin/admin/src/App.mjs +1 -1
- package/dist/admin/admin/src/App.mjs.map +1 -1
- package/dist/admin/admin/src/components/DismissibleBanner.js +60 -0
- package/dist/admin/admin/src/components/DismissibleBanner.js.map +1 -0
- package/dist/admin/admin/src/components/DismissibleBanner.mjs +58 -0
- package/dist/admin/admin/src/components/DismissibleBanner.mjs.map +1 -0
- package/dist/admin/admin/src/components/Form.js +11 -2
- package/dist/admin/admin/src/components/Form.js.map +1 -1
- package/dist/admin/admin/src/components/Form.mjs +11 -2
- package/dist/admin/admin/src/components/Form.mjs.map +1 -1
- package/dist/admin/admin/src/components/FormInputs/DateTime.js +1 -1
- package/dist/admin/admin/src/components/FormInputs/DateTime.js.map +1 -1
- package/dist/admin/admin/src/components/FormInputs/DateTime.mjs +1 -1
- package/dist/admin/admin/src/components/FormInputs/DateTime.mjs.map +1 -1
- package/dist/admin/admin/src/components/FormInputs/Time.js +1 -1
- package/dist/admin/admin/src/components/FormInputs/Time.js.map +1 -1
- package/dist/admin/admin/src/components/FormInputs/Time.mjs +1 -1
- package/dist/admin/admin/src/components/FormInputs/Time.mjs.map +1 -1
- package/dist/admin/admin/src/components/LanguageProvider.js +35 -1
- package/dist/admin/admin/src/components/LanguageProvider.js.map +1 -1
- package/dist/admin/admin/src/components/LanguageProvider.mjs +17 -2
- package/dist/admin/admin/src/components/LanguageProvider.mjs.map +1 -1
- package/dist/admin/admin/src/components/MainNav/NavUser.js +1 -2
- package/dist/admin/admin/src/components/MainNav/NavUser.js.map +1 -1
- package/dist/admin/admin/src/components/MainNav/NavUser.mjs +1 -2
- package/dist/admin/admin/src/components/MainNav/NavUser.mjs.map +1 -1
- package/dist/admin/admin/src/components/MediaLibraryBanner.js +85 -0
- package/dist/admin/admin/src/components/MediaLibraryBanner.js.map +1 -0
- package/dist/admin/admin/src/components/MediaLibraryBanner.mjs +83 -0
- package/dist/admin/admin/src/components/MediaLibraryBanner.mjs.map +1 -0
- package/dist/admin/admin/src/components/Providers.js +6 -6
- package/dist/admin/admin/src/components/Providers.js.map +1 -1
- package/dist/admin/admin/src/components/Providers.mjs +6 -6
- package/dist/admin/admin/src/components/Providers.mjs.map +1 -1
- package/dist/admin/admin/src/components/SubNav.js +113 -35
- package/dist/admin/admin/src/components/SubNav.js.map +1 -1
- package/dist/admin/admin/src/components/SubNav.mjs +115 -37
- package/dist/admin/admin/src/components/SubNav.mjs.map +1 -1
- package/dist/admin/admin/src/components/SubNavFolder.js +188 -0
- package/dist/admin/admin/src/components/SubNavFolder.js.map +1 -0
- package/dist/admin/admin/src/components/SubNavFolder.mjs +186 -0
- package/dist/admin/admin/src/components/SubNavFolder.mjs.map +1 -0
- package/dist/admin/admin/src/components/UpsellBanner.js +56 -86
- package/dist/admin/admin/src/components/UpsellBanner.js.map +1 -1
- package/dist/admin/admin/src/components/UpsellBanner.mjs +58 -88
- package/dist/admin/admin/src/components/UpsellBanner.mjs.map +1 -1
- package/dist/admin/admin/src/core/store/configure.js +14 -2
- package/dist/admin/admin/src/core/store/configure.js.map +1 -1
- package/dist/admin/admin/src/core/store/configure.mjs +14 -2
- package/dist/admin/admin/src/core/store/configure.mjs.map +1 -1
- package/dist/admin/admin/src/core/store/hooks.mjs +1 -1
- package/dist/admin/admin/src/features/Auth.js +162 -46
- package/dist/admin/admin/src/features/Auth.js.map +1 -1
- package/dist/admin/admin/src/features/Auth.mjs +164 -48
- package/dist/admin/admin/src/features/Auth.mjs.map +1 -1
- package/dist/admin/admin/src/features/Tracking.js.map +1 -1
- package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
- package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.js +19 -0
- package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.js.map +1 -0
- package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.mjs +17 -0
- package/dist/admin/admin/src/hooks/useRegisterUnsavedChanges.mjs.map +1 -0
- package/dist/admin/admin/src/hooks/{useIdleSessionLogout.js → useSessionKeepalive.js} +34 -27
- package/dist/admin/admin/src/hooks/useSessionKeepalive.js.map +1 -0
- package/dist/admin/admin/src/hooks/{useIdleSessionLogout.mjs → useSessionKeepalive.mjs} +34 -27
- package/dist/admin/admin/src/hooks/useSessionKeepalive.mjs.map +1 -0
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.js +2 -0
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.js.map +1 -1
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs +2 -0
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs.map +1 -1
- package/dist/admin/admin/src/pages/SessionsPage.js +2 -5
- package/dist/admin/admin/src/pages/SessionsPage.js.map +1 -1
- package/dist/admin/admin/src/pages/SessionsPage.mjs +2 -5
- package/dist/admin/admin/src/pages/SessionsPage.mjs.map +1 -1
- package/dist/admin/admin/src/render.js +6 -1
- package/dist/admin/admin/src/render.js.map +1 -1
- package/dist/admin/admin/src/render.mjs +6 -1
- package/dist/admin/admin/src/render.mjs.map +1 -1
- package/dist/admin/admin/src/translations/en.json.js +16 -0
- package/dist/admin/admin/src/translations/en.json.js.map +1 -1
- package/dist/admin/admin/src/translations/en.json.mjs +16 -0
- package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
- package/dist/admin/admin/src/utils/baseQuery.js +3 -13
- package/dist/admin/admin/src/utils/baseQuery.js.map +1 -1
- package/dist/admin/admin/src/utils/baseQuery.mjs +3 -13
- package/dist/admin/admin/src/utils/baseQuery.mjs.map +1 -1
- package/dist/admin/admin/src/utils/getFetchClient.js +34 -5
- package/dist/admin/admin/src/utils/getFetchClient.js.map +1 -1
- package/dist/admin/admin/src/utils/getFetchClient.mjs +34 -6
- package/dist/admin/admin/src/utils/getFetchClient.mjs.map +1 -1
- package/dist/admin/admin/src/utils/unsavedChangesRegistry.js +25 -0
- package/dist/admin/admin/src/utils/unsavedChangesRegistry.js.map +1 -0
- package/dist/admin/admin/src/utils/unsavedChangesRegistry.mjs +22 -0
- package/dist/admin/admin/src/utils/unsavedChangesRegistry.mjs.map +1 -0
- package/dist/admin/admin/tests/utils.js +14 -14
- package/dist/admin/admin/tests/utils.js.map +1 -1
- package/dist/admin/admin/tests/utils.mjs +14 -14
- package/dist/admin/admin/tests/utils.mjs.map +1 -1
- package/dist/admin/ee/admin/src/hooks/useAIAvailability.js +1 -6
- package/dist/admin/ee/admin/src/hooks/useAIAvailability.js.map +1 -1
- package/dist/admin/ee/admin/src/hooks/useAIAvailability.mjs +1 -6
- package/dist/admin/ee/admin/src/hooks/useAIAvailability.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.js +7 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.js.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.mjs +7 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/ApplicationInfoPage/components/AIUsage.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js +9 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs +9 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.js +0 -4
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.js.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.mjs +0 -4
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/SingleSignOnPage.mjs.map +1 -1
- package/dist/admin/index.js +1 -0
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/DismissibleBanner.d.ts +8 -0
- package/dist/admin/src/components/MediaLibraryBanner.d.ts +2 -0
- package/dist/admin/src/components/SubNav.d.ts +27 -8
- package/dist/admin/src/components/SubNavFolder.d.ts +15 -0
- package/dist/admin/src/features/Tracking.d.ts +2 -1
- package/dist/admin/src/hooks/useRegisterUnsavedChanges.d.ts +6 -0
- package/dist/admin/src/hooks/useSessionKeepalive.d.ts +88 -0
- package/dist/admin/src/services/admin.d.ts +1 -0
- package/dist/admin/src/utils/getFetchClient.d.ts +14 -6
- package/dist/admin/src/utils/unsavedChangesRegistry.d.ts +11 -0
- package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.d.ts +8 -0
- package/dist/ee/server/src/controllers/admin.d.ts.map +1 -1
- package/dist/ee/server/src/index.d.ts.map +1 -1
- package/dist/server/ee/server/src/controllers/admin.js +1 -5
- package/dist/server/ee/server/src/controllers/admin.js.map +1 -1
- package/dist/server/ee/server/src/controllers/admin.mjs +1 -5
- package/dist/server/ee/server/src/controllers/admin.mjs.map +1 -1
- package/dist/server/ee/server/src/index.js +2 -0
- package/dist/server/ee/server/src/index.js.map +1 -1
- package/dist/server/ee/server/src/index.mjs +2 -0
- package/dist/server/ee/server/src/index.mjs.map +1 -1
- package/dist/server/server/src/ai/controllers/ai.js +3 -3
- package/dist/server/server/src/ai/controllers/ai.js.map +1 -1
- package/dist/server/server/src/ai/controllers/ai.mjs +3 -3
- package/dist/server/server/src/ai/controllers/ai.mjs.map +1 -1
- package/dist/server/server/src/ai/services/ai.js +37 -12
- package/dist/server/server/src/ai/services/ai.js.map +1 -1
- package/dist/server/server/src/ai/services/ai.mjs +37 -12
- package/dist/server/server/src/ai/services/ai.mjs.map +1 -1
- package/dist/server/server/src/audit-logs/tokens.js +106 -0
- package/dist/server/server/src/audit-logs/tokens.js.map +1 -0
- package/dist/server/server/src/audit-logs/tokens.mjs +99 -0
- package/dist/server/server/src/audit-logs/tokens.mjs.map +1 -0
- package/dist/server/server/src/controllers/admin.js +10 -1
- package/dist/server/server/src/controllers/admin.js.map +1 -1
- package/dist/server/server/src/controllers/admin.mjs +10 -1
- package/dist/server/server/src/controllers/admin.mjs.map +1 -1
- package/dist/server/server/src/services/api-token.js +106 -4
- package/dist/server/server/src/services/api-token.js.map +1 -1
- package/dist/server/server/src/services/api-token.mjs +107 -5
- package/dist/server/server/src/services/api-token.mjs.map +1 -1
- package/dist/server/server/src/services/transfer/token.js +56 -4
- package/dist/server/server/src/services/transfer/token.js.map +1 -1
- package/dist/server/server/src/services/transfer/token.mjs +57 -5
- package/dist/server/server/src/services/transfer/token.mjs.map +1 -1
- package/dist/server/src/ai/services/ai.d.ts +3 -1
- package/dist/server/src/ai/services/ai.d.ts.map +1 -1
- package/dist/server/src/audit-logs/tokens.d.ts +86 -0
- package/dist/server/src/audit-logs/tokens.d.ts.map +1 -0
- package/dist/server/src/controllers/admin.d.ts +1 -0
- package/dist/server/src/controllers/admin.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +1 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/services/api-token.d.ts.map +1 -1
- package/dist/server/src/services/transfer/token.d.ts.map +1 -1
- package/dist/shared/contracts/admin.d.ts +1 -0
- package/dist/shared/contracts/admin.d.ts.map +1 -1
- package/dist/shared/contracts/shared.d.ts +1 -0
- package/dist/shared/contracts/shared.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/admin/admin/src/hooks/useIdleSessionLogout.js.map +0 -1
- package/dist/admin/admin/src/hooks/useIdleSessionLogout.mjs.map +0 -1
- package/dist/admin/src/hooks/useIdleSessionLogout.d.ts +0 -87
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticatedLayout.js","sources":["../../../../../admin/src/layouts/AuthenticatedLayout.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport packageInfo from '@strapi/admin/package.json';\nimport { Box, Flex, SkipToContent } from '@strapi/design-system';\nimport { DndProvider } from 'react-dnd';\nimport { HTML5Backend } from 'react-dnd-html5-backend';\nimport { useIntl } from 'react-intl';\nimport lt from 'semver/functions/lt';\nimport valid from 'semver/functions/valid';\n\nimport { LazyOutlet } from '../components/LazyOutlet';\nimport { LeftMenu } from '../components/LeftMenu';\nimport { NpsSurvey } from '../components/NpsSurvey';\nimport { Page } from '../components/PageHelpers';\nimport { PluginsInitializer } from '../components/PluginsInitializer';\nimport { PrivateRoute } from '../components/PrivateRoute';\nimport { UpsellBanner } from '../components/UpsellBanner';\nimport { AppInfoProvider } from '../features/AppInfo';\nimport { useAuth } from '../features/Auth';\nimport { useConfiguration } from '../features/Configuration';\nimport { useStrapiApp } from '../features/StrapiApp';\nimport { useTracking } from '../features/Tracking';\nimport { useMenu } from '../hooks/useMenu';\nimport { useInformationQuery } from '../services/admin';\nimport { hashAdminUserEmail } from '../utils/users';\n\nconst { version: strapiVersion } = packageInfo;\n\nconst AdminLayout = () => {\n const { formatMessage } = useIntl();\n const userInfo = useAuth('AuthenticatedApp', (state) => state.user);\n const [userId, setUserId] = React.useState<string>();\n const { showReleaseNotification } = useConfiguration('AuthenticatedApp');\n\n const { data: appInfo, isLoading: isLoadingAppInfo } = useInformationQuery();\n const [tagName, setTagName] = React.useState<string>(strapiVersion);\n\n React.useEffect(() => {\n if (showReleaseNotification) {\n fetch('https://api.github.com/repos/strapi/strapi/releases/latest')\n .then(async (res) => {\n if (!res.ok) {\n return;\n }\n\n const response = (await res.json()) as { tag_name: string | null | undefined };\n\n if (!response.tag_name) {\n throw new Error();\n }\n\n setTagName(response.tag_name);\n })\n .catch(() => {\n /**\n * silence is golden & we'll use the strapiVersion as a fallback\n */\n });\n }\n }, [showReleaseNotification]);\n\n React.useEffect(() => {\n hashAdminUserEmail(userInfo).then((id) => {\n if (id) {\n setUserId(id);\n }\n });\n }, [userInfo]);\n\n const { trackUsage } = useTracking();\n\n const {\n isLoading: isLoadingMenu,\n generalSectionLinks,\n pluginsSectionLinks,\n topMobileNavigation,\n burgerMobileNavigation,\n } = useMenu(checkLatestStrapiVersion(strapiVersion, tagName), appInfo?.currentEnvironment);\n\n const getAllWidgets = useStrapiApp('TrackingProvider', (state) => state.widgets.getAll);\n const projectId = appInfo?.projectId;\n React.useEffect(() => {\n if (projectId) {\n trackUsage('didAccessAuthenticatedAdministration', {\n registeredWidgets: getAllWidgets().map((widget) => widget.uid),\n projectId,\n });\n }\n }, [projectId, getAllWidgets, trackUsage]);\n\n // We don't need to wait for the release query to be fetched before rendering the plugins\n // however, we need the appInfos and the permissions\n if (isLoadingMenu || isLoadingAppInfo) {\n return <Page.Loading />;\n }\n\n return (\n <AppInfoProvider\n {...appInfo}\n userId={userId}\n latestStrapiReleaseTag={tagName}\n shouldUpdateStrapi={checkLatestStrapiVersion(strapiVersion, tagName)}\n >\n <NpsSurvey />\n <PluginsInitializer>\n <DndProvider backend={HTML5Backend}>\n <Box background=\"neutral100\">\n <SkipToContent>\n {formatMessage({ id: 'skipToContent', defaultMessage: 'Skip to content' })}\n </SkipToContent>\n <Flex\n height=\"100dvh\"\n direction={{\n initial: 'column',\n large: 'row',\n }}\n alignItems=\"flex-start\"\n >\n <LeftMenu\n generalSectionLinks={generalSectionLinks}\n pluginsSectionLinks={pluginsSectionLinks}\n topMobileNavigation={topMobileNavigation}\n burgerMobileNavigation={burgerMobileNavigation}\n />\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n flex={1}\n overflow=\"auto\"\n width=\"100%\"\n height={{\n initial: 'auto',\n large: '100%',\n }}\n >\n <UpsellBanner />\n {/*\n * Top-level Suspense only — nested layouts (Settings, Content Manager) use\n * LazyOutlet with useNavigation so in-app navigations show loading in the content\n * column without hiding section side navs.\n */}\n <LazyOutlet suspenseOnly />\n </Flex>\n </Flex>\n </Box>\n </DndProvider>\n </PluginsInitializer>\n </AppInfoProvider>\n );\n};\n\nconst PrivateAdminLayout = () => {\n return (\n <PrivateRoute>\n <AdminLayout />\n </PrivateRoute>\n );\n};\n\nconst checkLatestStrapiVersion = (\n currentPackageVersion: string,\n latestPublishedVersion: string = ''\n): boolean => {\n if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {\n return false;\n }\n\n return lt(currentPackageVersion, latestPublishedVersion);\n};\n\nexport { AdminLayout, PrivateAdminLayout };\n"],"names":["version","strapiVersion","packageInfo","AdminLayout","formatMessage","useIntl","userInfo","useAuth","state","user","userId","setUserId","React","useState","showReleaseNotification","useConfiguration","data","appInfo","isLoading","isLoadingAppInfo","useInformationQuery","tagName","setTagName","useEffect","fetch","then","res","ok","response","json","tag_name","Error","catch","hashAdminUserEmail","id","trackUsage","useTracking","isLoadingMenu","generalSectionLinks","pluginsSectionLinks","topMobileNavigation","burgerMobileNavigation","useMenu","checkLatestStrapiVersion","currentEnvironment","getAllWidgets","useStrapiApp","widgets","getAll","projectId","registeredWidgets","map","widget","uid","_jsx","Page","Loading","_jsxs","AppInfoProvider","latestStrapiReleaseTag","shouldUpdateStrapi","NpsSurvey","PluginsInitializer","DndProvider","backend","HTML5Backend","Box","background","SkipToContent","defaultMessage","Flex","height","direction","initial","large","alignItems","LeftMenu","flex","overflow","width","UpsellBanner","LazyOutlet","suspenseOnly","PrivateAdminLayout","PrivateRoute","currentPackageVersion","latestPublishedVersion","valid","lt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthenticatedLayout.js","sources":["../../../../../admin/src/layouts/AuthenticatedLayout.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport packageInfo from '@strapi/admin/package.json';\nimport { Box, Flex, SkipToContent } from '@strapi/design-system';\nimport { DndProvider } from 'react-dnd';\nimport { HTML5Backend } from 'react-dnd-html5-backend';\nimport { useIntl } from 'react-intl';\nimport lt from 'semver/functions/lt';\nimport valid from 'semver/functions/valid';\n\nimport { LazyOutlet } from '../components/LazyOutlet';\nimport { LeftMenu } from '../components/LeftMenu';\nimport { MediaLibraryBanner } from '../components/MediaLibraryBanner';\nimport { NpsSurvey } from '../components/NpsSurvey';\nimport { Page } from '../components/PageHelpers';\nimport { PluginsInitializer } from '../components/PluginsInitializer';\nimport { PrivateRoute } from '../components/PrivateRoute';\nimport { UpsellBanner } from '../components/UpsellBanner';\nimport { AppInfoProvider } from '../features/AppInfo';\nimport { useAuth } from '../features/Auth';\nimport { useConfiguration } from '../features/Configuration';\nimport { useStrapiApp } from '../features/StrapiApp';\nimport { useTracking } from '../features/Tracking';\nimport { useMenu } from '../hooks/useMenu';\nimport { useInformationQuery } from '../services/admin';\nimport { hashAdminUserEmail } from '../utils/users';\n\nconst { version: strapiVersion } = packageInfo;\n\nconst AdminLayout = () => {\n const { formatMessage } = useIntl();\n const userInfo = useAuth('AuthenticatedApp', (state) => state.user);\n const [userId, setUserId] = React.useState<string>();\n const { showReleaseNotification } = useConfiguration('AuthenticatedApp');\n\n const { data: appInfo, isLoading: isLoadingAppInfo } = useInformationQuery();\n const [tagName, setTagName] = React.useState<string>(strapiVersion);\n\n React.useEffect(() => {\n if (showReleaseNotification) {\n fetch('https://api.github.com/repos/strapi/strapi/releases/latest')\n .then(async (res) => {\n if (!res.ok) {\n return;\n }\n\n const response = (await res.json()) as { tag_name: string | null | undefined };\n\n if (!response.tag_name) {\n throw new Error();\n }\n\n setTagName(response.tag_name);\n })\n .catch(() => {\n /**\n * silence is golden & we'll use the strapiVersion as a fallback\n */\n });\n }\n }, [showReleaseNotification]);\n\n React.useEffect(() => {\n hashAdminUserEmail(userInfo).then((id) => {\n if (id) {\n setUserId(id);\n }\n });\n }, [userInfo]);\n\n const { trackUsage } = useTracking();\n\n const {\n isLoading: isLoadingMenu,\n generalSectionLinks,\n pluginsSectionLinks,\n topMobileNavigation,\n burgerMobileNavigation,\n } = useMenu(checkLatestStrapiVersion(strapiVersion, tagName), appInfo?.currentEnvironment);\n\n const getAllWidgets = useStrapiApp('TrackingProvider', (state) => state.widgets.getAll);\n const projectId = appInfo?.projectId;\n React.useEffect(() => {\n if (projectId) {\n trackUsage('didAccessAuthenticatedAdministration', {\n registeredWidgets: getAllWidgets().map((widget) => widget.uid),\n projectId,\n });\n }\n }, [projectId, getAllWidgets, trackUsage]);\n\n // We don't need to wait for the release query to be fetched before rendering the plugins\n // however, we need the appInfos and the permissions\n if (isLoadingMenu || isLoadingAppInfo) {\n return <Page.Loading />;\n }\n\n return (\n <AppInfoProvider\n {...appInfo}\n userId={userId}\n latestStrapiReleaseTag={tagName}\n shouldUpdateStrapi={checkLatestStrapiVersion(strapiVersion, tagName)}\n >\n <NpsSurvey />\n <PluginsInitializer>\n <DndProvider backend={HTML5Backend}>\n <Box background=\"neutral100\">\n <SkipToContent>\n {formatMessage({ id: 'skipToContent', defaultMessage: 'Skip to content' })}\n </SkipToContent>\n <Flex\n height=\"100dvh\"\n direction={{\n initial: 'column',\n large: 'row',\n }}\n alignItems=\"flex-start\"\n >\n <LeftMenu\n generalSectionLinks={generalSectionLinks}\n pluginsSectionLinks={pluginsSectionLinks}\n topMobileNavigation={topMobileNavigation}\n burgerMobileNavigation={burgerMobileNavigation}\n />\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n flex={1}\n overflow=\"auto\"\n width=\"100%\"\n height={{\n initial: 'auto',\n large: '100%',\n }}\n >\n <UpsellBanner />\n <MediaLibraryBanner />\n {/*\n * Top-level Suspense only — nested layouts (Settings, Content Manager) use\n * LazyOutlet with useNavigation so in-app navigations show loading in the content\n * column without hiding section side navs.\n */}\n <LazyOutlet suspenseOnly />\n </Flex>\n </Flex>\n </Box>\n </DndProvider>\n </PluginsInitializer>\n </AppInfoProvider>\n );\n};\n\nconst PrivateAdminLayout = () => {\n return (\n <PrivateRoute>\n <AdminLayout />\n </PrivateRoute>\n );\n};\n\nconst checkLatestStrapiVersion = (\n currentPackageVersion: string,\n latestPublishedVersion: string = ''\n): boolean => {\n if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {\n return false;\n }\n\n return lt(currentPackageVersion, latestPublishedVersion);\n};\n\nexport { AdminLayout, PrivateAdminLayout };\n"],"names":["version","strapiVersion","packageInfo","AdminLayout","formatMessage","useIntl","userInfo","useAuth","state","user","userId","setUserId","React","useState","showReleaseNotification","useConfiguration","data","appInfo","isLoading","isLoadingAppInfo","useInformationQuery","tagName","setTagName","useEffect","fetch","then","res","ok","response","json","tag_name","Error","catch","hashAdminUserEmail","id","trackUsage","useTracking","isLoadingMenu","generalSectionLinks","pluginsSectionLinks","topMobileNavigation","burgerMobileNavigation","useMenu","checkLatestStrapiVersion","currentEnvironment","getAllWidgets","useStrapiApp","widgets","getAll","projectId","registeredWidgets","map","widget","uid","_jsx","Page","Loading","_jsxs","AppInfoProvider","latestStrapiReleaseTag","shouldUpdateStrapi","NpsSurvey","PluginsInitializer","DndProvider","backend","HTML5Backend","Box","background","SkipToContent","defaultMessage","Flex","height","direction","initial","large","alignItems","LeftMenu","flex","overflow","width","UpsellBanner","MediaLibraryBanner","LazyOutlet","suspenseOnly","PrivateAdminLayout","PrivateRoute","currentPackageVersion","latestPublishedVersion","valid","lt"],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ import lt from 'semver/functions/lt';
|
|
|
9
9
|
import valid from 'semver/functions/valid';
|
|
10
10
|
import { LazyOutlet } from '../components/LazyOutlet.mjs';
|
|
11
11
|
import { LeftMenu } from '../components/LeftMenu.mjs';
|
|
12
|
+
import { MediaLibraryBanner } from '../components/MediaLibraryBanner.mjs';
|
|
12
13
|
import { NpsSurvey } from '../components/NpsSurvey.mjs';
|
|
13
14
|
import { Page } from '../components/PageHelpers.mjs';
|
|
14
15
|
import { PluginsInitializer } from '../components/PluginsInitializer.mjs';
|
|
@@ -125,6 +126,7 @@ const AdminLayout = ()=>{
|
|
|
125
126
|
},
|
|
126
127
|
children: [
|
|
127
128
|
/*#__PURE__*/ jsx(UpsellBanner, {}),
|
|
129
|
+
/*#__PURE__*/ jsx(MediaLibraryBanner, {}),
|
|
128
130
|
/*#__PURE__*/ jsx(LazyOutlet, {
|
|
129
131
|
suspenseOnly: true
|
|
130
132
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthenticatedLayout.mjs","sources":["../../../../../admin/src/layouts/AuthenticatedLayout.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport packageInfo from '@strapi/admin/package.json';\nimport { Box, Flex, SkipToContent } from '@strapi/design-system';\nimport { DndProvider } from 'react-dnd';\nimport { HTML5Backend } from 'react-dnd-html5-backend';\nimport { useIntl } from 'react-intl';\nimport lt from 'semver/functions/lt';\nimport valid from 'semver/functions/valid';\n\nimport { LazyOutlet } from '../components/LazyOutlet';\nimport { LeftMenu } from '../components/LeftMenu';\nimport { NpsSurvey } from '../components/NpsSurvey';\nimport { Page } from '../components/PageHelpers';\nimport { PluginsInitializer } from '../components/PluginsInitializer';\nimport { PrivateRoute } from '../components/PrivateRoute';\nimport { UpsellBanner } from '../components/UpsellBanner';\nimport { AppInfoProvider } from '../features/AppInfo';\nimport { useAuth } from '../features/Auth';\nimport { useConfiguration } from '../features/Configuration';\nimport { useStrapiApp } from '../features/StrapiApp';\nimport { useTracking } from '../features/Tracking';\nimport { useMenu } from '../hooks/useMenu';\nimport { useInformationQuery } from '../services/admin';\nimport { hashAdminUserEmail } from '../utils/users';\n\nconst { version: strapiVersion } = packageInfo;\n\nconst AdminLayout = () => {\n const { formatMessage } = useIntl();\n const userInfo = useAuth('AuthenticatedApp', (state) => state.user);\n const [userId, setUserId] = React.useState<string>();\n const { showReleaseNotification } = useConfiguration('AuthenticatedApp');\n\n const { data: appInfo, isLoading: isLoadingAppInfo } = useInformationQuery();\n const [tagName, setTagName] = React.useState<string>(strapiVersion);\n\n React.useEffect(() => {\n if (showReleaseNotification) {\n fetch('https://api.github.com/repos/strapi/strapi/releases/latest')\n .then(async (res) => {\n if (!res.ok) {\n return;\n }\n\n const response = (await res.json()) as { tag_name: string | null | undefined };\n\n if (!response.tag_name) {\n throw new Error();\n }\n\n setTagName(response.tag_name);\n })\n .catch(() => {\n /**\n * silence is golden & we'll use the strapiVersion as a fallback\n */\n });\n }\n }, [showReleaseNotification]);\n\n React.useEffect(() => {\n hashAdminUserEmail(userInfo).then((id) => {\n if (id) {\n setUserId(id);\n }\n });\n }, [userInfo]);\n\n const { trackUsage } = useTracking();\n\n const {\n isLoading: isLoadingMenu,\n generalSectionLinks,\n pluginsSectionLinks,\n topMobileNavigation,\n burgerMobileNavigation,\n } = useMenu(checkLatestStrapiVersion(strapiVersion, tagName), appInfo?.currentEnvironment);\n\n const getAllWidgets = useStrapiApp('TrackingProvider', (state) => state.widgets.getAll);\n const projectId = appInfo?.projectId;\n React.useEffect(() => {\n if (projectId) {\n trackUsage('didAccessAuthenticatedAdministration', {\n registeredWidgets: getAllWidgets().map((widget) => widget.uid),\n projectId,\n });\n }\n }, [projectId, getAllWidgets, trackUsage]);\n\n // We don't need to wait for the release query to be fetched before rendering the plugins\n // however, we need the appInfos and the permissions\n if (isLoadingMenu || isLoadingAppInfo) {\n return <Page.Loading />;\n }\n\n return (\n <AppInfoProvider\n {...appInfo}\n userId={userId}\n latestStrapiReleaseTag={tagName}\n shouldUpdateStrapi={checkLatestStrapiVersion(strapiVersion, tagName)}\n >\n <NpsSurvey />\n <PluginsInitializer>\n <DndProvider backend={HTML5Backend}>\n <Box background=\"neutral100\">\n <SkipToContent>\n {formatMessage({ id: 'skipToContent', defaultMessage: 'Skip to content' })}\n </SkipToContent>\n <Flex\n height=\"100dvh\"\n direction={{\n initial: 'column',\n large: 'row',\n }}\n alignItems=\"flex-start\"\n >\n <LeftMenu\n generalSectionLinks={generalSectionLinks}\n pluginsSectionLinks={pluginsSectionLinks}\n topMobileNavigation={topMobileNavigation}\n burgerMobileNavigation={burgerMobileNavigation}\n />\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n flex={1}\n overflow=\"auto\"\n width=\"100%\"\n height={{\n initial: 'auto',\n large: '100%',\n }}\n >\n <UpsellBanner />\n {/*\n * Top-level Suspense only — nested layouts (Settings, Content Manager) use\n * LazyOutlet with useNavigation so in-app navigations show loading in the content\n * column without hiding section side navs.\n */}\n <LazyOutlet suspenseOnly />\n </Flex>\n </Flex>\n </Box>\n </DndProvider>\n </PluginsInitializer>\n </AppInfoProvider>\n );\n};\n\nconst PrivateAdminLayout = () => {\n return (\n <PrivateRoute>\n <AdminLayout />\n </PrivateRoute>\n );\n};\n\nconst checkLatestStrapiVersion = (\n currentPackageVersion: string,\n latestPublishedVersion: string = ''\n): boolean => {\n if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {\n return false;\n }\n\n return lt(currentPackageVersion, latestPublishedVersion);\n};\n\nexport { AdminLayout, PrivateAdminLayout };\n"],"names":["version","strapiVersion","packageInfo","AdminLayout","formatMessage","useIntl","userInfo","useAuth","state","user","userId","setUserId","React","useState","showReleaseNotification","useConfiguration","data","appInfo","isLoading","isLoadingAppInfo","useInformationQuery","tagName","setTagName","useEffect","fetch","then","res","ok","response","json","tag_name","Error","catch","hashAdminUserEmail","id","trackUsage","useTracking","isLoadingMenu","generalSectionLinks","pluginsSectionLinks","topMobileNavigation","burgerMobileNavigation","useMenu","checkLatestStrapiVersion","currentEnvironment","getAllWidgets","useStrapiApp","widgets","getAll","projectId","registeredWidgets","map","widget","uid","_jsx","Page","Loading","_jsxs","AppInfoProvider","latestStrapiReleaseTag","shouldUpdateStrapi","NpsSurvey","PluginsInitializer","DndProvider","backend","HTML5Backend","Box","background","SkipToContent","defaultMessage","Flex","height","direction","initial","large","alignItems","LeftMenu","flex","overflow","width","UpsellBanner","LazyOutlet","suspenseOnly","PrivateAdminLayout","PrivateRoute","currentPackageVersion","latestPublishedVersion","valid","lt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuthenticatedLayout.mjs","sources":["../../../../../admin/src/layouts/AuthenticatedLayout.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport packageInfo from '@strapi/admin/package.json';\nimport { Box, Flex, SkipToContent } from '@strapi/design-system';\nimport { DndProvider } from 'react-dnd';\nimport { HTML5Backend } from 'react-dnd-html5-backend';\nimport { useIntl } from 'react-intl';\nimport lt from 'semver/functions/lt';\nimport valid from 'semver/functions/valid';\n\nimport { LazyOutlet } from '../components/LazyOutlet';\nimport { LeftMenu } from '../components/LeftMenu';\nimport { MediaLibraryBanner } from '../components/MediaLibraryBanner';\nimport { NpsSurvey } from '../components/NpsSurvey';\nimport { Page } from '../components/PageHelpers';\nimport { PluginsInitializer } from '../components/PluginsInitializer';\nimport { PrivateRoute } from '../components/PrivateRoute';\nimport { UpsellBanner } from '../components/UpsellBanner';\nimport { AppInfoProvider } from '../features/AppInfo';\nimport { useAuth } from '../features/Auth';\nimport { useConfiguration } from '../features/Configuration';\nimport { useStrapiApp } from '../features/StrapiApp';\nimport { useTracking } from '../features/Tracking';\nimport { useMenu } from '../hooks/useMenu';\nimport { useInformationQuery } from '../services/admin';\nimport { hashAdminUserEmail } from '../utils/users';\n\nconst { version: strapiVersion } = packageInfo;\n\nconst AdminLayout = () => {\n const { formatMessage } = useIntl();\n const userInfo = useAuth('AuthenticatedApp', (state) => state.user);\n const [userId, setUserId] = React.useState<string>();\n const { showReleaseNotification } = useConfiguration('AuthenticatedApp');\n\n const { data: appInfo, isLoading: isLoadingAppInfo } = useInformationQuery();\n const [tagName, setTagName] = React.useState<string>(strapiVersion);\n\n React.useEffect(() => {\n if (showReleaseNotification) {\n fetch('https://api.github.com/repos/strapi/strapi/releases/latest')\n .then(async (res) => {\n if (!res.ok) {\n return;\n }\n\n const response = (await res.json()) as { tag_name: string | null | undefined };\n\n if (!response.tag_name) {\n throw new Error();\n }\n\n setTagName(response.tag_name);\n })\n .catch(() => {\n /**\n * silence is golden & we'll use the strapiVersion as a fallback\n */\n });\n }\n }, [showReleaseNotification]);\n\n React.useEffect(() => {\n hashAdminUserEmail(userInfo).then((id) => {\n if (id) {\n setUserId(id);\n }\n });\n }, [userInfo]);\n\n const { trackUsage } = useTracking();\n\n const {\n isLoading: isLoadingMenu,\n generalSectionLinks,\n pluginsSectionLinks,\n topMobileNavigation,\n burgerMobileNavigation,\n } = useMenu(checkLatestStrapiVersion(strapiVersion, tagName), appInfo?.currentEnvironment);\n\n const getAllWidgets = useStrapiApp('TrackingProvider', (state) => state.widgets.getAll);\n const projectId = appInfo?.projectId;\n React.useEffect(() => {\n if (projectId) {\n trackUsage('didAccessAuthenticatedAdministration', {\n registeredWidgets: getAllWidgets().map((widget) => widget.uid),\n projectId,\n });\n }\n }, [projectId, getAllWidgets, trackUsage]);\n\n // We don't need to wait for the release query to be fetched before rendering the plugins\n // however, we need the appInfos and the permissions\n if (isLoadingMenu || isLoadingAppInfo) {\n return <Page.Loading />;\n }\n\n return (\n <AppInfoProvider\n {...appInfo}\n userId={userId}\n latestStrapiReleaseTag={tagName}\n shouldUpdateStrapi={checkLatestStrapiVersion(strapiVersion, tagName)}\n >\n <NpsSurvey />\n <PluginsInitializer>\n <DndProvider backend={HTML5Backend}>\n <Box background=\"neutral100\">\n <SkipToContent>\n {formatMessage({ id: 'skipToContent', defaultMessage: 'Skip to content' })}\n </SkipToContent>\n <Flex\n height=\"100dvh\"\n direction={{\n initial: 'column',\n large: 'row',\n }}\n alignItems=\"flex-start\"\n >\n <LeftMenu\n generalSectionLinks={generalSectionLinks}\n pluginsSectionLinks={pluginsSectionLinks}\n topMobileNavigation={topMobileNavigation}\n burgerMobileNavigation={burgerMobileNavigation}\n />\n <Flex\n direction=\"column\"\n alignItems=\"stretch\"\n flex={1}\n overflow=\"auto\"\n width=\"100%\"\n height={{\n initial: 'auto',\n large: '100%',\n }}\n >\n <UpsellBanner />\n <MediaLibraryBanner />\n {/*\n * Top-level Suspense only — nested layouts (Settings, Content Manager) use\n * LazyOutlet with useNavigation so in-app navigations show loading in the content\n * column without hiding section side navs.\n */}\n <LazyOutlet suspenseOnly />\n </Flex>\n </Flex>\n </Box>\n </DndProvider>\n </PluginsInitializer>\n </AppInfoProvider>\n );\n};\n\nconst PrivateAdminLayout = () => {\n return (\n <PrivateRoute>\n <AdminLayout />\n </PrivateRoute>\n );\n};\n\nconst checkLatestStrapiVersion = (\n currentPackageVersion: string,\n latestPublishedVersion: string = ''\n): boolean => {\n if (!valid(currentPackageVersion) || !valid(latestPublishedVersion)) {\n return false;\n }\n\n return lt(currentPackageVersion, latestPublishedVersion);\n};\n\nexport { AdminLayout, PrivateAdminLayout };\n"],"names":["version","strapiVersion","packageInfo","AdminLayout","formatMessage","useIntl","userInfo","useAuth","state","user","userId","setUserId","React","useState","showReleaseNotification","useConfiguration","data","appInfo","isLoading","isLoadingAppInfo","useInformationQuery","tagName","setTagName","useEffect","fetch","then","res","ok","response","json","tag_name","Error","catch","hashAdminUserEmail","id","trackUsage","useTracking","isLoadingMenu","generalSectionLinks","pluginsSectionLinks","topMobileNavigation","burgerMobileNavigation","useMenu","checkLatestStrapiVersion","currentEnvironment","getAllWidgets","useStrapiApp","widgets","getAll","projectId","registeredWidgets","map","widget","uid","_jsx","Page","Loading","_jsxs","AppInfoProvider","latestStrapiReleaseTag","shouldUpdateStrapi","NpsSurvey","PluginsInitializer","DndProvider","backend","HTML5Backend","Box","background","SkipToContent","defaultMessage","Flex","height","direction","initial","large","alignItems","LeftMenu","flex","overflow","width","UpsellBanner","MediaLibraryBanner","LazyOutlet","suspenseOnly","PrivateAdminLayout","PrivateRoute","currentPackageVersion","latestPublishedVersion","valid","lt"],"mappings":"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"}
|
|
@@ -5,7 +5,6 @@ var React = require('react');
|
|
|
5
5
|
var designSystem = require('@strapi/design-system');
|
|
6
6
|
var icons = require('@strapi/icons');
|
|
7
7
|
var reactIntl = require('react-intl');
|
|
8
|
-
var reactRouterDom = require('react-router-dom');
|
|
9
8
|
var ConfirmDialog = require('../components/ConfirmDialog.js');
|
|
10
9
|
var Layout = require('../components/Layouts/Layout.js');
|
|
11
10
|
var PageHelpers = require('../components/PageHelpers.js');
|
|
@@ -40,7 +39,6 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
|
40
39
|
* SessionsPage
|
|
41
40
|
* -----------------------------------------------------------------------------------------------*/ const SessionsPage = ()=>{
|
|
42
41
|
const { formatMessage } = reactIntl.useIntl();
|
|
43
|
-
const navigate = reactRouterDom.useNavigate();
|
|
44
42
|
const { toggleNotification } = Notifications.useNotification();
|
|
45
43
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler.useAPIErrorHandler();
|
|
46
44
|
const logout = Auth.useAuth('SessionsPage', (state)=>state.logout);
|
|
@@ -48,11 +46,10 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
|
48
46
|
const [revokeSession] = auth.useRevokeSessionMutation();
|
|
49
47
|
const [revokeAllSessions] = auth.useRevokeAllSessionsMutation();
|
|
50
48
|
const handleLogoutAndRedirect = React__namespace.useCallback(async ()=>{
|
|
49
|
+
// Auth.logout navigates to login after confirm + mutation (and may prompt first).
|
|
51
50
|
await logout();
|
|
52
|
-
navigate('/auth/login');
|
|
53
51
|
}, [
|
|
54
|
-
logout
|
|
55
|
-
navigate
|
|
52
|
+
logout
|
|
56
53
|
]);
|
|
57
54
|
const notifyError = React__namespace.useCallback((error)=>{
|
|
58
55
|
toggleNotification({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionsPage.js","sources":["../../../../../admin/src/pages/SessionsPage.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n Badge,\n Box,\n Button,\n Dialog,\n Flex,\n IconButton,\n Table,\n Tbody,\n Td,\n Th,\n Thead,\n Tr,\n Typography,\n} from '@strapi/design-system';\nimport { SignOut } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { useNavigate } from 'react-router-dom';\n\nimport { ConfirmDialog } from '../components/ConfirmDialog';\nimport { Layouts } from '../components/Layouts/Layout';\nimport { Page } from '../components/PageHelpers';\nimport { RelativeTime } from '../components/RelativeTime';\nimport { useAuth } from '../features/Auth';\nimport { useNotification } from '../features/Notifications';\nimport { useAPIErrorHandler } from '../hooks/useAPIErrorHandler';\nimport {\n useGetActiveSessionsQuery,\n useRevokeAllSessionsMutation,\n useRevokeSessionMutation,\n} from '../services/auth';\nimport { isBaseQueryError } from '../utils/baseQuery';\n\nimport type { SanitizedAdminSession } from '../../../shared/contracts/sessions';\n\n/* -------------------------------------------------------------------------------------------------\n * SessionsPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst SessionsPage = () => {\n const { formatMessage } = useIntl();\n const navigate = useNavigate();\n const { toggleNotification } = useNotification();\n const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n const logout = useAuth('SessionsPage', (state) => state.logout);\n\n const { data: sessions = [], isLoading, error } = useGetActiveSessionsQuery();\n const [revokeSession] = useRevokeSessionMutation();\n const [revokeAllSessions] = useRevokeAllSessionsMutation();\n\n const handleLogoutAndRedirect = React.useCallback(async () => {\n await logout();\n navigate('/auth/login');\n }, [logout, navigate]);\n\n const notifyError = React.useCallback(\n (error?: unknown) => {\n toggleNotification({\n type: 'danger',\n message:\n error && isBaseQueryError(error)\n ? formatAPIError(error)\n : formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n },\n [formatAPIError, formatMessage, toggleNotification]\n );\n\n const runSessionMutation = React.useCallback(\n async (\n action: () => Promise<{ error?: unknown } | { data: unknown } | void>,\n onSuccess: () => void | Promise<void>\n ) => {\n try {\n const res = await action();\n\n if (res && 'error' in res && res.error) {\n notifyError(res.error);\n return;\n }\n\n await onSuccess();\n } catch {\n notifyError();\n }\n },\n [notifyError]\n );\n\n const handleRevoke = async (session: SanitizedAdminSession) => {\n await runSessionMutation(\n () => revokeSession(session.id),\n async () => {\n if (session.current) {\n await handleLogoutAndRedirect();\n return;\n }\n\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revoke.success',\n defaultMessage: 'Session ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeOthers = async () => {\n await runSessionMutation(\n () => revokeAllSessions({ keepCurrent: true }),\n () => {\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revokeOthers.success',\n defaultMessage: 'Other sessions ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeAll = async () => {\n await runSessionMutation(() => revokeAllSessions(undefined), handleLogoutAndRedirect);\n };\n\n if (isLoading) {\n return <Page.Loading />;\n }\n\n if (error) {\n return <Page.Error />;\n }\n\n return (\n <Page.Main>\n <Page.Title>\n {formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n </Page.Title>\n <Layouts.Header\n title={formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n subtitle={formatMessage({\n id: 'Settings.sessions.subtitle',\n defaultMessage: 'These are the devices and sessions currently signed in to your account.',\n })}\n primaryAction={\n sessions.length > 0 ? (\n <Flex gap={2}>\n {sessions.length > 1 ? (\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"secondary\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers',\n defaultMessage: 'Log out of other devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeOthers}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers.confirm',\n defaultMessage:\n 'Are you sure? This will end every other active session. You will stay signed in on this device.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n ) : null}\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"danger-light\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll',\n defaultMessage: 'Log out of all devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeAll}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll.confirm',\n defaultMessage:\n 'Are you sure? This will end every active session, including this one, and you will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n ) : undefined\n }\n />\n <Layouts.Content>\n <Box background=\"neutral0\" hasRadius shadow=\"filterShadow\">\n <Table colCount={4} rowCount={sessions.length}>\n <Thead>\n <Tr>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.device', defaultMessage: 'Device' })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.loginAt',\n defaultMessage: 'Signed in',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.lastActiveAt',\n defaultMessage: 'Last used',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.actions', defaultMessage: 'Actions' })}\n </Typography>\n </Th>\n </Tr>\n </Thead>\n <Tbody>\n {sessions.map((session) => (\n <Tr key={session.id}>\n <Td>\n <Flex gap={2}>\n <Typography textColor=\"neutral800\">\n {session.deviceName ??\n (session.deviceId\n ? session.deviceId.slice(0, 8)\n : formatMessage({\n id: 'Settings.sessions.unknownDevice',\n defaultMessage: 'Unknown device',\n }))}\n </Typography>\n {session.current && (\n <Badge>\n {formatMessage({\n id: 'Settings.sessions.current',\n defaultMessage: 'This device',\n })}\n </Badge>\n )}\n </Flex>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.loginAt ? (\n <RelativeTime timestamp={new Date(session.loginAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.lastActiveAt ? (\n <RelativeTime timestamp={new Date(session.lastActiveAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Flex justifyContent=\"end\" onClick={(e) => e.stopPropagation()}>\n <Dialog.Root>\n <Dialog.Trigger>\n <IconButton\n label={formatMessage({\n id: 'Settings.sessions.revoke',\n defaultMessage: 'End session',\n })}\n variant=\"ghost\"\n >\n <SignOut />\n </IconButton>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={() => handleRevoke(session)}>\n {session.current\n ? formatMessage({\n id: 'Settings.sessions.revoke.confirmCurrent',\n defaultMessage:\n 'This is the device you are currently using. Ending this session will log you out.',\n })\n : formatMessage({\n id: 'Settings.sessions.revoke.confirm',\n defaultMessage:\n 'Are you sure you want to end this session? The device will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n </Td>\n </Tr>\n ))}\n </Tbody>\n </Table>\n </Box>\n </Layouts.Content>\n </Page.Main>\n );\n};\n\nexport { SessionsPage };\n"],"names":["SessionsPage","formatMessage","useIntl","navigate","useNavigate","toggleNotification","useNotification","_unstableFormatAPIError","formatAPIError","useAPIErrorHandler","logout","useAuth","state","data","sessions","isLoading","error","useGetActiveSessionsQuery","revokeSession","useRevokeSessionMutation","revokeAllSessions","useRevokeAllSessionsMutation","handleLogoutAndRedirect","React","useCallback","notifyError","type","message","isBaseQueryError","id","defaultMessage","runSessionMutation","action","onSuccess","res","handleRevoke","session","current","handleRevokeOthers","keepCurrent","handleRevokeAll","undefined","_jsx","Page","Loading","Error","_jsxs","Main","Title","Layouts","Header","title","subtitle","primaryAction","length","Flex","gap","Dialog","Root","Trigger","Button","variant","startIcon","SignOut","ConfirmDialog","onConfirm","Content","Box","background","hasRadius","shadow","Table","colCount","rowCount","Thead","Tr","Th","Typography","Tbody","map","Td","textColor","deviceName","deviceId","slice","Badge","loginAt","RelativeTime","timestamp","Date","lastActiveAt","justifyContent","onClick","e","stopPropagation","IconButton","label"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionsPage.js","sources":["../../../../../admin/src/pages/SessionsPage.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n Badge,\n Box,\n Button,\n Dialog,\n Flex,\n IconButton,\n Table,\n Tbody,\n Td,\n Th,\n Thead,\n Tr,\n Typography,\n} from '@strapi/design-system';\nimport { SignOut } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { ConfirmDialog } from '../components/ConfirmDialog';\nimport { Layouts } from '../components/Layouts/Layout';\nimport { Page } from '../components/PageHelpers';\nimport { RelativeTime } from '../components/RelativeTime';\nimport { useAuth } from '../features/Auth';\nimport { useNotification } from '../features/Notifications';\nimport { useAPIErrorHandler } from '../hooks/useAPIErrorHandler';\nimport {\n useGetActiveSessionsQuery,\n useRevokeAllSessionsMutation,\n useRevokeSessionMutation,\n} from '../services/auth';\nimport { isBaseQueryError } from '../utils/baseQuery';\n\nimport type { SanitizedAdminSession } from '../../../shared/contracts/sessions';\n\n/* -------------------------------------------------------------------------------------------------\n * SessionsPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst SessionsPage = () => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n const logout = useAuth('SessionsPage', (state) => state.logout);\n\n const { data: sessions = [], isLoading, error } = useGetActiveSessionsQuery();\n const [revokeSession] = useRevokeSessionMutation();\n const [revokeAllSessions] = useRevokeAllSessionsMutation();\n\n const handleLogoutAndRedirect = React.useCallback(async () => {\n // Auth.logout navigates to login after confirm + mutation (and may prompt first).\n await logout();\n }, [logout]);\n\n const notifyError = React.useCallback(\n (error?: unknown) => {\n toggleNotification({\n type: 'danger',\n message:\n error && isBaseQueryError(error)\n ? formatAPIError(error)\n : formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n },\n [formatAPIError, formatMessage, toggleNotification]\n );\n\n const runSessionMutation = React.useCallback(\n async (\n action: () => Promise<{ error?: unknown } | { data: unknown } | void>,\n onSuccess: () => void | Promise<void>\n ) => {\n try {\n const res = await action();\n\n if (res && 'error' in res && res.error) {\n notifyError(res.error);\n return;\n }\n\n await onSuccess();\n } catch {\n notifyError();\n }\n },\n [notifyError]\n );\n\n const handleRevoke = async (session: SanitizedAdminSession) => {\n await runSessionMutation(\n () => revokeSession(session.id),\n async () => {\n if (session.current) {\n await handleLogoutAndRedirect();\n return;\n }\n\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revoke.success',\n defaultMessage: 'Session ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeOthers = async () => {\n await runSessionMutation(\n () => revokeAllSessions({ keepCurrent: true }),\n () => {\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revokeOthers.success',\n defaultMessage: 'Other sessions ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeAll = async () => {\n await runSessionMutation(() => revokeAllSessions(undefined), handleLogoutAndRedirect);\n };\n\n if (isLoading) {\n return <Page.Loading />;\n }\n\n if (error) {\n return <Page.Error />;\n }\n\n return (\n <Page.Main>\n <Page.Title>\n {formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n </Page.Title>\n <Layouts.Header\n title={formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n subtitle={formatMessage({\n id: 'Settings.sessions.subtitle',\n defaultMessage: 'These are the devices and sessions currently signed in to your account.',\n })}\n primaryAction={\n sessions.length > 0 ? (\n <Flex gap={2}>\n {sessions.length > 1 ? (\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"secondary\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers',\n defaultMessage: 'Log out of other devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeOthers}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers.confirm',\n defaultMessage:\n 'Are you sure? This will end every other active session. You will stay signed in on this device.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n ) : null}\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"danger-light\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll',\n defaultMessage: 'Log out of all devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeAll}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll.confirm',\n defaultMessage:\n 'Are you sure? This will end every active session, including this one, and you will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n ) : undefined\n }\n />\n <Layouts.Content>\n <Box background=\"neutral0\" hasRadius shadow=\"filterShadow\">\n <Table colCount={4} rowCount={sessions.length}>\n <Thead>\n <Tr>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.device', defaultMessage: 'Device' })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.loginAt',\n defaultMessage: 'Signed in',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.lastActiveAt',\n defaultMessage: 'Last used',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.actions', defaultMessage: 'Actions' })}\n </Typography>\n </Th>\n </Tr>\n </Thead>\n <Tbody>\n {sessions.map((session) => (\n <Tr key={session.id}>\n <Td>\n <Flex gap={2}>\n <Typography textColor=\"neutral800\">\n {session.deviceName ??\n (session.deviceId\n ? session.deviceId.slice(0, 8)\n : formatMessage({\n id: 'Settings.sessions.unknownDevice',\n defaultMessage: 'Unknown device',\n }))}\n </Typography>\n {session.current && (\n <Badge>\n {formatMessage({\n id: 'Settings.sessions.current',\n defaultMessage: 'This device',\n })}\n </Badge>\n )}\n </Flex>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.loginAt ? (\n <RelativeTime timestamp={new Date(session.loginAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.lastActiveAt ? (\n <RelativeTime timestamp={new Date(session.lastActiveAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Flex justifyContent=\"end\" onClick={(e) => e.stopPropagation()}>\n <Dialog.Root>\n <Dialog.Trigger>\n <IconButton\n label={formatMessage({\n id: 'Settings.sessions.revoke',\n defaultMessage: 'End session',\n })}\n variant=\"ghost\"\n >\n <SignOut />\n </IconButton>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={() => handleRevoke(session)}>\n {session.current\n ? formatMessage({\n id: 'Settings.sessions.revoke.confirmCurrent',\n defaultMessage:\n 'This is the device you are currently using. Ending this session will log you out.',\n })\n : formatMessage({\n id: 'Settings.sessions.revoke.confirm',\n defaultMessage:\n 'Are you sure you want to end this session? The device will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n </Td>\n </Tr>\n ))}\n </Tbody>\n </Table>\n </Box>\n </Layouts.Content>\n </Page.Main>\n );\n};\n\nexport { SessionsPage };\n"],"names":["SessionsPage","formatMessage","useIntl","toggleNotification","useNotification","_unstableFormatAPIError","formatAPIError","useAPIErrorHandler","logout","useAuth","state","data","sessions","isLoading","error","useGetActiveSessionsQuery","revokeSession","useRevokeSessionMutation","revokeAllSessions","useRevokeAllSessionsMutation","handleLogoutAndRedirect","React","useCallback","notifyError","type","message","isBaseQueryError","id","defaultMessage","runSessionMutation","action","onSuccess","res","handleRevoke","session","current","handleRevokeOthers","keepCurrent","handleRevokeAll","undefined","_jsx","Page","Loading","Error","_jsxs","Main","Title","Layouts","Header","title","subtitle","primaryAction","length","Flex","gap","Dialog","Root","Trigger","Button","variant","startIcon","SignOut","ConfirmDialog","onConfirm","Content","Box","background","hasRadius","shadow","Table","colCount","rowCount","Thead","Tr","Th","Typography","Tbody","map","Td","textColor","deviceName","deviceId","slice","Badge","loginAt","RelativeTime","timestamp","Date","lastActiveAt","justifyContent","onClick","e","stopPropagation","IconButton","label"],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@ import * as React from 'react';
|
|
|
3
3
|
import { Flex, Dialog, Button, Box, Table, Thead, Tr, Th, Typography, Tbody, Td, Badge, IconButton } from '@strapi/design-system';
|
|
4
4
|
import { SignOut } from '@strapi/icons';
|
|
5
5
|
import { useIntl } from 'react-intl';
|
|
6
|
-
import { useNavigate } from 'react-router-dom';
|
|
7
6
|
import { ConfirmDialog } from '../components/ConfirmDialog.mjs';
|
|
8
7
|
import { Layouts } from '../components/Layouts/Layout.mjs';
|
|
9
8
|
import { Page } from '../components/PageHelpers.mjs';
|
|
@@ -18,7 +17,6 @@ import { isBaseQueryError } from '../utils/baseQuery.mjs';
|
|
|
18
17
|
* SessionsPage
|
|
19
18
|
* -----------------------------------------------------------------------------------------------*/ const SessionsPage = ()=>{
|
|
20
19
|
const { formatMessage } = useIntl();
|
|
21
|
-
const navigate = useNavigate();
|
|
22
20
|
const { toggleNotification } = useNotification();
|
|
23
21
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
|
24
22
|
const logout = useAuth('SessionsPage', (state)=>state.logout);
|
|
@@ -26,11 +24,10 @@ import { isBaseQueryError } from '../utils/baseQuery.mjs';
|
|
|
26
24
|
const [revokeSession] = useRevokeSessionMutation();
|
|
27
25
|
const [revokeAllSessions] = useRevokeAllSessionsMutation();
|
|
28
26
|
const handleLogoutAndRedirect = React.useCallback(async ()=>{
|
|
27
|
+
// Auth.logout navigates to login after confirm + mutation (and may prompt first).
|
|
29
28
|
await logout();
|
|
30
|
-
navigate('/auth/login');
|
|
31
29
|
}, [
|
|
32
|
-
logout
|
|
33
|
-
navigate
|
|
30
|
+
logout
|
|
34
31
|
]);
|
|
35
32
|
const notifyError = React.useCallback((error)=>{
|
|
36
33
|
toggleNotification({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionsPage.mjs","sources":["../../../../../admin/src/pages/SessionsPage.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n Badge,\n Box,\n Button,\n Dialog,\n Flex,\n IconButton,\n Table,\n Tbody,\n Td,\n Th,\n Thead,\n Tr,\n Typography,\n} from '@strapi/design-system';\nimport { SignOut } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { useNavigate } from 'react-router-dom';\n\nimport { ConfirmDialog } from '../components/ConfirmDialog';\nimport { Layouts } from '../components/Layouts/Layout';\nimport { Page } from '../components/PageHelpers';\nimport { RelativeTime } from '../components/RelativeTime';\nimport { useAuth } from '../features/Auth';\nimport { useNotification } from '../features/Notifications';\nimport { useAPIErrorHandler } from '../hooks/useAPIErrorHandler';\nimport {\n useGetActiveSessionsQuery,\n useRevokeAllSessionsMutation,\n useRevokeSessionMutation,\n} from '../services/auth';\nimport { isBaseQueryError } from '../utils/baseQuery';\n\nimport type { SanitizedAdminSession } from '../../../shared/contracts/sessions';\n\n/* -------------------------------------------------------------------------------------------------\n * SessionsPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst SessionsPage = () => {\n const { formatMessage } = useIntl();\n const navigate = useNavigate();\n const { toggleNotification } = useNotification();\n const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n const logout = useAuth('SessionsPage', (state) => state.logout);\n\n const { data: sessions = [], isLoading, error } = useGetActiveSessionsQuery();\n const [revokeSession] = useRevokeSessionMutation();\n const [revokeAllSessions] = useRevokeAllSessionsMutation();\n\n const handleLogoutAndRedirect = React.useCallback(async () => {\n await logout();\n navigate('/auth/login');\n }, [logout, navigate]);\n\n const notifyError = React.useCallback(\n (error?: unknown) => {\n toggleNotification({\n type: 'danger',\n message:\n error && isBaseQueryError(error)\n ? formatAPIError(error)\n : formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n },\n [formatAPIError, formatMessage, toggleNotification]\n );\n\n const runSessionMutation = React.useCallback(\n async (\n action: () => Promise<{ error?: unknown } | { data: unknown } | void>,\n onSuccess: () => void | Promise<void>\n ) => {\n try {\n const res = await action();\n\n if (res && 'error' in res && res.error) {\n notifyError(res.error);\n return;\n }\n\n await onSuccess();\n } catch {\n notifyError();\n }\n },\n [notifyError]\n );\n\n const handleRevoke = async (session: SanitizedAdminSession) => {\n await runSessionMutation(\n () => revokeSession(session.id),\n async () => {\n if (session.current) {\n await handleLogoutAndRedirect();\n return;\n }\n\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revoke.success',\n defaultMessage: 'Session ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeOthers = async () => {\n await runSessionMutation(\n () => revokeAllSessions({ keepCurrent: true }),\n () => {\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revokeOthers.success',\n defaultMessage: 'Other sessions ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeAll = async () => {\n await runSessionMutation(() => revokeAllSessions(undefined), handleLogoutAndRedirect);\n };\n\n if (isLoading) {\n return <Page.Loading />;\n }\n\n if (error) {\n return <Page.Error />;\n }\n\n return (\n <Page.Main>\n <Page.Title>\n {formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n </Page.Title>\n <Layouts.Header\n title={formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n subtitle={formatMessage({\n id: 'Settings.sessions.subtitle',\n defaultMessage: 'These are the devices and sessions currently signed in to your account.',\n })}\n primaryAction={\n sessions.length > 0 ? (\n <Flex gap={2}>\n {sessions.length > 1 ? (\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"secondary\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers',\n defaultMessage: 'Log out of other devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeOthers}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers.confirm',\n defaultMessage:\n 'Are you sure? This will end every other active session. You will stay signed in on this device.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n ) : null}\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"danger-light\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll',\n defaultMessage: 'Log out of all devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeAll}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll.confirm',\n defaultMessage:\n 'Are you sure? This will end every active session, including this one, and you will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n ) : undefined\n }\n />\n <Layouts.Content>\n <Box background=\"neutral0\" hasRadius shadow=\"filterShadow\">\n <Table colCount={4} rowCount={sessions.length}>\n <Thead>\n <Tr>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.device', defaultMessage: 'Device' })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.loginAt',\n defaultMessage: 'Signed in',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.lastActiveAt',\n defaultMessage: 'Last used',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.actions', defaultMessage: 'Actions' })}\n </Typography>\n </Th>\n </Tr>\n </Thead>\n <Tbody>\n {sessions.map((session) => (\n <Tr key={session.id}>\n <Td>\n <Flex gap={2}>\n <Typography textColor=\"neutral800\">\n {session.deviceName ??\n (session.deviceId\n ? session.deviceId.slice(0, 8)\n : formatMessage({\n id: 'Settings.sessions.unknownDevice',\n defaultMessage: 'Unknown device',\n }))}\n </Typography>\n {session.current && (\n <Badge>\n {formatMessage({\n id: 'Settings.sessions.current',\n defaultMessage: 'This device',\n })}\n </Badge>\n )}\n </Flex>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.loginAt ? (\n <RelativeTime timestamp={new Date(session.loginAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.lastActiveAt ? (\n <RelativeTime timestamp={new Date(session.lastActiveAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Flex justifyContent=\"end\" onClick={(e) => e.stopPropagation()}>\n <Dialog.Root>\n <Dialog.Trigger>\n <IconButton\n label={formatMessage({\n id: 'Settings.sessions.revoke',\n defaultMessage: 'End session',\n })}\n variant=\"ghost\"\n >\n <SignOut />\n </IconButton>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={() => handleRevoke(session)}>\n {session.current\n ? formatMessage({\n id: 'Settings.sessions.revoke.confirmCurrent',\n defaultMessage:\n 'This is the device you are currently using. Ending this session will log you out.',\n })\n : formatMessage({\n id: 'Settings.sessions.revoke.confirm',\n defaultMessage:\n 'Are you sure you want to end this session? The device will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n </Td>\n </Tr>\n ))}\n </Tbody>\n </Table>\n </Box>\n </Layouts.Content>\n </Page.Main>\n );\n};\n\nexport { SessionsPage };\n"],"names":["SessionsPage","formatMessage","useIntl","navigate","useNavigate","toggleNotification","useNotification","_unstableFormatAPIError","formatAPIError","useAPIErrorHandler","logout","useAuth","state","data","sessions","isLoading","error","useGetActiveSessionsQuery","revokeSession","useRevokeSessionMutation","revokeAllSessions","useRevokeAllSessionsMutation","handleLogoutAndRedirect","React","useCallback","notifyError","type","message","isBaseQueryError","id","defaultMessage","runSessionMutation","action","onSuccess","res","handleRevoke","session","current","handleRevokeOthers","keepCurrent","handleRevokeAll","undefined","_jsx","Page","Loading","Error","_jsxs","Main","Title","Layouts","Header","title","subtitle","primaryAction","length","Flex","gap","Dialog","Root","Trigger","Button","variant","startIcon","SignOut","ConfirmDialog","onConfirm","Content","Box","background","hasRadius","shadow","Table","colCount","rowCount","Thead","Tr","Th","Typography","Tbody","map","Td","textColor","deviceName","deviceId","slice","Badge","loginAt","RelativeTime","timestamp","Date","lastActiveAt","justifyContent","onClick","e","stopPropagation","IconButton","label"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionsPage.mjs","sources":["../../../../../admin/src/pages/SessionsPage.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n Badge,\n Box,\n Button,\n Dialog,\n Flex,\n IconButton,\n Table,\n Tbody,\n Td,\n Th,\n Thead,\n Tr,\n Typography,\n} from '@strapi/design-system';\nimport { SignOut } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { ConfirmDialog } from '../components/ConfirmDialog';\nimport { Layouts } from '../components/Layouts/Layout';\nimport { Page } from '../components/PageHelpers';\nimport { RelativeTime } from '../components/RelativeTime';\nimport { useAuth } from '../features/Auth';\nimport { useNotification } from '../features/Notifications';\nimport { useAPIErrorHandler } from '../hooks/useAPIErrorHandler';\nimport {\n useGetActiveSessionsQuery,\n useRevokeAllSessionsMutation,\n useRevokeSessionMutation,\n} from '../services/auth';\nimport { isBaseQueryError } from '../utils/baseQuery';\n\nimport type { SanitizedAdminSession } from '../../../shared/contracts/sessions';\n\n/* -------------------------------------------------------------------------------------------------\n * SessionsPage\n * -----------------------------------------------------------------------------------------------*/\n\nconst SessionsPage = () => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();\n const logout = useAuth('SessionsPage', (state) => state.logout);\n\n const { data: sessions = [], isLoading, error } = useGetActiveSessionsQuery();\n const [revokeSession] = useRevokeSessionMutation();\n const [revokeAllSessions] = useRevokeAllSessionsMutation();\n\n const handleLogoutAndRedirect = React.useCallback(async () => {\n // Auth.logout navigates to login after confirm + mutation (and may prompt first).\n await logout();\n }, [logout]);\n\n const notifyError = React.useCallback(\n (error?: unknown) => {\n toggleNotification({\n type: 'danger',\n message:\n error && isBaseQueryError(error)\n ? formatAPIError(error)\n : formatMessage({ id: 'notification.error', defaultMessage: 'An error occurred' }),\n });\n },\n [formatAPIError, formatMessage, toggleNotification]\n );\n\n const runSessionMutation = React.useCallback(\n async (\n action: () => Promise<{ error?: unknown } | { data: unknown } | void>,\n onSuccess: () => void | Promise<void>\n ) => {\n try {\n const res = await action();\n\n if (res && 'error' in res && res.error) {\n notifyError(res.error);\n return;\n }\n\n await onSuccess();\n } catch {\n notifyError();\n }\n },\n [notifyError]\n );\n\n const handleRevoke = async (session: SanitizedAdminSession) => {\n await runSessionMutation(\n () => revokeSession(session.id),\n async () => {\n if (session.current) {\n await handleLogoutAndRedirect();\n return;\n }\n\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revoke.success',\n defaultMessage: 'Session ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeOthers = async () => {\n await runSessionMutation(\n () => revokeAllSessions({ keepCurrent: true }),\n () => {\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: 'Settings.sessions.revokeOthers.success',\n defaultMessage: 'Other sessions ended',\n }),\n });\n }\n );\n };\n\n const handleRevokeAll = async () => {\n await runSessionMutation(() => revokeAllSessions(undefined), handleLogoutAndRedirect);\n };\n\n if (isLoading) {\n return <Page.Loading />;\n }\n\n if (error) {\n return <Page.Error />;\n }\n\n return (\n <Page.Main>\n <Page.Title>\n {formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n </Page.Title>\n <Layouts.Header\n title={formatMessage({\n id: 'Settings.sessions.title',\n defaultMessage: 'Active Devices',\n })}\n subtitle={formatMessage({\n id: 'Settings.sessions.subtitle',\n defaultMessage: 'These are the devices and sessions currently signed in to your account.',\n })}\n primaryAction={\n sessions.length > 0 ? (\n <Flex gap={2}>\n {sessions.length > 1 ? (\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"secondary\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers',\n defaultMessage: 'Log out of other devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeOthers}>\n {formatMessage({\n id: 'Settings.sessions.revokeOthers.confirm',\n defaultMessage:\n 'Are you sure? This will end every other active session. You will stay signed in on this device.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n ) : null}\n <Dialog.Root>\n <Dialog.Trigger>\n <Button variant=\"danger-light\" startIcon={<SignOut />}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll',\n defaultMessage: 'Log out of all devices',\n })}\n </Button>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={handleRevokeAll}>\n {formatMessage({\n id: 'Settings.sessions.revokeAll.confirm',\n defaultMessage:\n 'Are you sure? This will end every active session, including this one, and you will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n ) : undefined\n }\n />\n <Layouts.Content>\n <Box background=\"neutral0\" hasRadius shadow=\"filterShadow\">\n <Table colCount={4} rowCount={sessions.length}>\n <Thead>\n <Tr>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.device', defaultMessage: 'Device' })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.loginAt',\n defaultMessage: 'Signed in',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({\n id: 'Settings.sessions.lastActiveAt',\n defaultMessage: 'Last used',\n })}\n </Typography>\n </Th>\n <Th>\n <Typography variant=\"sigma\">\n {formatMessage({ id: 'Settings.sessions.actions', defaultMessage: 'Actions' })}\n </Typography>\n </Th>\n </Tr>\n </Thead>\n <Tbody>\n {sessions.map((session) => (\n <Tr key={session.id}>\n <Td>\n <Flex gap={2}>\n <Typography textColor=\"neutral800\">\n {session.deviceName ??\n (session.deviceId\n ? session.deviceId.slice(0, 8)\n : formatMessage({\n id: 'Settings.sessions.unknownDevice',\n defaultMessage: 'Unknown device',\n }))}\n </Typography>\n {session.current && (\n <Badge>\n {formatMessage({\n id: 'Settings.sessions.current',\n defaultMessage: 'This device',\n })}\n </Badge>\n )}\n </Flex>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.loginAt ? (\n <RelativeTime timestamp={new Date(session.loginAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Typography textColor=\"neutral800\">\n {session.lastActiveAt ? (\n <RelativeTime timestamp={new Date(session.lastActiveAt)} />\n ) : (\n '-'\n )}\n </Typography>\n </Td>\n <Td>\n <Flex justifyContent=\"end\" onClick={(e) => e.stopPropagation()}>\n <Dialog.Root>\n <Dialog.Trigger>\n <IconButton\n label={formatMessage({\n id: 'Settings.sessions.revoke',\n defaultMessage: 'End session',\n })}\n variant=\"ghost\"\n >\n <SignOut />\n </IconButton>\n </Dialog.Trigger>\n <ConfirmDialog onConfirm={() => handleRevoke(session)}>\n {session.current\n ? formatMessage({\n id: 'Settings.sessions.revoke.confirmCurrent',\n defaultMessage:\n 'This is the device you are currently using. Ending this session will log you out.',\n })\n : formatMessage({\n id: 'Settings.sessions.revoke.confirm',\n defaultMessage:\n 'Are you sure you want to end this session? The device will need to log in again.',\n })}\n </ConfirmDialog>\n </Dialog.Root>\n </Flex>\n </Td>\n </Tr>\n ))}\n </Tbody>\n </Table>\n </Box>\n </Layouts.Content>\n </Page.Main>\n );\n};\n\nexport { SessionsPage };\n"],"names":["SessionsPage","formatMessage","useIntl","toggleNotification","useNotification","_unstableFormatAPIError","formatAPIError","useAPIErrorHandler","logout","useAuth","state","data","sessions","isLoading","error","useGetActiveSessionsQuery","revokeSession","useRevokeSessionMutation","revokeAllSessions","useRevokeAllSessionsMutation","handleLogoutAndRedirect","React","useCallback","notifyError","type","message","isBaseQueryError","id","defaultMessage","runSessionMutation","action","onSuccess","res","handleRevoke","session","current","handleRevokeOthers","keepCurrent","handleRevokeAll","undefined","_jsx","Page","Loading","Error","_jsxs","Main","Title","Layouts","Header","title","subtitle","primaryAction","length","Flex","gap","Dialog","Root","Trigger","Button","variant","startIcon","SignOut","ConfirmDialog","onConfirm","Content","Box","background","hasRadius","shadow","Table","colCount","rowCount","Thead","Tr","Th","Typography","Tbody","map","Td","textColor","deviceName","deviceId","slice","Badge","loginAt","RelativeTime","timestamp","Date","lastActiveAt","justifyContent","onClick","e","stopPropagation","IconButton","label"],"mappings":";;;;;;;;;;;;;;;AAoCA;;AAEkG,2GAE5FA,YAAAA,GAAe,IAAA;IACnB,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;IAC1B,MAAM,EAAEC,kBAAkB,EAAE,GAAGC,eAAAA,EAAAA;AAC/B,IAAA,MAAM,EAAEC,uBAAAA,EAAyBC,cAAc,EAAE,GAAGC,kBAAAA,EAAAA;AACpD,IAAA,MAAMC,SAASC,OAAAA,CAAQ,cAAA,EAAgB,CAACC,KAAAA,GAAUA,MAAMF,MAAM,CAAA;IAE9D,MAAM,EAAEG,MAAMC,QAAAA,GAAW,EAAE,EAAEC,SAAS,EAAEC,KAAK,EAAE,GAAGC,yBAAAA,EAAAA;IAClD,MAAM,CAACC,cAAc,GAAGC,wBAAAA,EAAAA;IACxB,MAAM,CAACC,kBAAkB,GAAGC,4BAAAA,EAAAA;IAE5B,MAAMC,uBAAAA,GAA0BC,KAAAA,CAAMC,WAAW,CAAC,UAAA;;QAEhD,MAAMd,MAAAA,EAAAA;IACR,CAAA,EAAG;AAACA,QAAAA;AAAO,KAAA,CAAA;AAEX,IAAA,MAAMe,WAAAA,GAAcF,KAAAA,CAAMC,WAAW,CACnC,CAACR,KAAAA,GAAAA;QACCX,kBAAAA,CAAmB;YACjBqB,IAAAA,EAAM,QAAA;AACNC,YAAAA,OAAAA,EACEX,KAAAA,IAASY,gBAAAA,CAAiBZ,KAAAA,CAAAA,GACtBR,cAAAA,CAAeQ,SACfb,aAAAA,CAAc;gBAAE0B,EAAAA,EAAI,oBAAA;gBAAsBC,cAAAA,EAAgB;AAAoB,aAAA;AACtF,SAAA,CAAA;IACF,CAAA,EACA;AAACtB,QAAAA,cAAAA;AAAgBL,QAAAA,aAAAA;AAAeE,QAAAA;AAAmB,KAAA,CAAA;AAGrD,IAAA,MAAM0B,kBAAAA,GAAqBR,KAAAA,CAAMC,WAAW,CAC1C,OACEQ,MAAAA,EACAC,SAAAA,GAAAA;QAEA,IAAI;AACF,YAAA,MAAMC,MAAM,MAAMF,MAAAA,EAAAA;AAElB,YAAA,IAAIE,GAAAA,IAAO,OAAA,IAAWA,GAAAA,IAAOA,GAAAA,CAAIlB,KAAK,EAAE;AACtCS,gBAAAA,WAAAA,CAAYS,IAAIlB,KAAK,CAAA;AACrB,gBAAA;AACF,YAAA;YAEA,MAAMiB,SAAAA,EAAAA;AACR,QAAA,CAAA,CAAE,OAAM;AACNR,YAAAA,WAAAA,EAAAA;AACF,QAAA;IACF,CAAA,EACA;AAACA,QAAAA;AAAY,KAAA,CAAA;AAGf,IAAA,MAAMU,eAAe,OAAOC,OAAAA,GAAAA;AAC1B,QAAA,MAAML,kBAAAA,CACJ,IAAMb,aAAAA,CAAckB,OAAAA,CAAQP,EAAE,CAAA,EAC9B,UAAA;YACE,IAAIO,OAAAA,CAAQC,OAAO,EAAE;gBACnB,MAAMf,uBAAAA,EAAAA;AACN,gBAAA;AACF,YAAA;YAEAjB,kBAAAA,CAAmB;gBACjBqB,IAAAA,EAAM,SAAA;AACNC,gBAAAA,OAAAA,EAASxB,aAAAA,CAAc;oBACrB0B,EAAAA,EAAI,kCAAA;oBACJC,cAAAA,EAAgB;AAClB,iBAAA;AACF,aAAA,CAAA;AACF,QAAA,CAAA,CAAA;AAEJ,IAAA,CAAA;AAEA,IAAA,MAAMQ,kBAAAA,GAAqB,UAAA;QACzB,MAAMP,kBAAAA,CACJ,IAAMX,iBAAAA,CAAkB;gBAAEmB,WAAAA,EAAa;aAAK,CAAA,EAC5C,IAAA;YACElC,kBAAAA,CAAmB;gBACjBqB,IAAAA,EAAM,SAAA;AACNC,gBAAAA,OAAAA,EAASxB,aAAAA,CAAc;oBACrB0B,EAAAA,EAAI,wCAAA;oBACJC,cAAAA,EAAgB;AAClB,iBAAA;AACF,aAAA,CAAA;AACF,QAAA,CAAA,CAAA;AAEJ,IAAA,CAAA;AAEA,IAAA,MAAMU,eAAAA,GAAkB,UAAA;QACtB,MAAMT,kBAAAA,CAAmB,IAAMX,iBAAAA,CAAkBqB,SAAAA,CAAAA,EAAYnB,uBAAAA,CAAAA;AAC/D,IAAA,CAAA;AAEA,IAAA,IAAIP,SAAAA,EAAW;QACb,qBAAO2B,GAAA,CAACC,KAAKC,OAAO,EAAA,EAAA,CAAA;AACtB,IAAA;AAEA,IAAA,IAAI5B,KAAAA,EAAO;QACT,qBAAO0B,GAAA,CAACC,KAAKE,KAAK,EAAA,EAAA,CAAA;AACpB,IAAA;IAEA,qBACEC,IAAA,CAACH,KAAKI,IAAI,EAAA;;AACR,0BAAAL,GAAA,CAACC,KAAKK,KAAK,EAAA;0BACR7C,aAAAA,CAAc;oBACb0B,EAAAA,EAAI,yBAAA;oBACJC,cAAAA,EAAgB;AAClB,iBAAA;;AAEF,0BAAAY,GAAA,CAACO,QAAQC,MAAM,EAAA;AACbC,gBAAAA,KAAAA,EAAOhD,aAAAA,CAAc;oBACnB0B,EAAAA,EAAI,yBAAA;oBACJC,cAAAA,EAAgB;AAClB,iBAAA,CAAA;AACAsB,gBAAAA,QAAAA,EAAUjD,aAAAA,CAAc;oBACtB0B,EAAAA,EAAI,4BAAA;oBACJC,cAAAA,EAAgB;AAClB,iBAAA,CAAA;AACAuB,gBAAAA,aAAAA,EACEvC,QAAAA,CAASwC,MAAM,GAAG,CAAA,iBAChBR,IAAA,CAACS,IAAAA,EAAAA;oBAAKC,GAAAA,EAAK,CAAA;;AACR1C,wBAAAA,QAAAA,CAASwC,MAAM,GAAG,CAAA,iBACjBR,IAAA,CAACW,OAAOC,IAAI,EAAA;;AACV,8CAAAhB,GAAA,CAACe,OAAOE,OAAO,EAAA;AACb,oCAAA,QAAA,gBAAAjB,GAAA,CAACkB,MAAAA,EAAAA;wCAAOC,OAAAA,EAAQ,WAAA;AAAYC,wCAAAA,SAAAA,gBAAWpB,GAAA,CAACqB,OAAAA,EAAAA,EAAAA,CAAAA;kDACrC5D,aAAAA,CAAc;4CACb0B,EAAAA,EAAI,gCAAA;4CACJC,cAAAA,EAAgB;AAClB,yCAAA;;;8CAGJY,GAAA,CAACsB,aAAAA,EAAAA;oCAAcC,SAAAA,EAAW3B,kBAAAA;8CACvBnC,aAAAA,CAAc;wCACb0B,EAAAA,EAAI,wCAAA;wCACJC,cAAAA,EACE;AACJ,qCAAA;;;AAGF,yBAAA,CAAA,GAAA,IAAA;AACJ,sCAAAgB,IAAA,CAACW,OAAOC,IAAI,EAAA;;AACV,8CAAAhB,GAAA,CAACe,OAAOE,OAAO,EAAA;AACb,oCAAA,QAAA,gBAAAjB,GAAA,CAACkB,MAAAA,EAAAA;wCAAOC,OAAAA,EAAQ,cAAA;AAAeC,wCAAAA,SAAAA,gBAAWpB,GAAA,CAACqB,OAAAA,EAAAA,EAAAA,CAAAA;kDACxC5D,aAAAA,CAAc;4CACb0B,EAAAA,EAAI,6BAAA;4CACJC,cAAAA,EAAgB;AAClB,yCAAA;;;8CAGJY,GAAA,CAACsB,aAAAA,EAAAA;oCAAcC,SAAAA,EAAWzB,eAAAA;8CACvBrC,aAAAA,CAAc;wCACb0B,EAAAA,EAAI,qCAAA;wCACJC,cAAAA,EACE;AACJ,qCAAA;;;;;AAIJW,iBAAAA,CAAAA,GAAAA;;AAGR,0BAAAC,GAAA,CAACO,QAAQiB,OAAO,EAAA;AACd,gBAAA,QAAA,gBAAAxB,GAAA,CAACyB,GAAAA,EAAAA;oBAAIC,UAAAA,EAAW,UAAA;oBAAWC,SAAS,EAAA,IAAA;oBAACC,MAAAA,EAAO,cAAA;AAC1C,oBAAA,QAAA,gBAAAxB,IAAA,CAACyB,KAAAA,EAAAA;wBAAMC,QAAAA,EAAU,CAAA;AAAGC,wBAAAA,QAAAA,EAAU3D,SAASwC,MAAM;;0CAC3CZ,GAAA,CAACgC,KAAAA,EAAAA;AACC,gCAAA,QAAA,gBAAA5B,IAAA,CAAC6B,EAAAA,EAAAA;;sDACCjC,GAAA,CAACkC,EAAAA,EAAAA;AACC,4CAAA,QAAA,gBAAAlC,GAAA,CAACmC,UAAAA,EAAAA;gDAAWhB,OAAAA,EAAQ,OAAA;0DACjB1D,aAAAA,CAAc;oDAAE0B,EAAAA,EAAI,0BAAA;oDAA4BC,cAAAA,EAAgB;AAAS,iDAAA;;;sDAG9EY,GAAA,CAACkC,EAAAA,EAAAA;AACC,4CAAA,QAAA,gBAAAlC,GAAA,CAACmC,UAAAA,EAAAA;gDAAWhB,OAAAA,EAAQ,OAAA;0DACjB1D,aAAAA,CAAc;oDACb0B,EAAAA,EAAI,2BAAA;oDACJC,cAAAA,EAAgB;AAClB,iDAAA;;;sDAGJY,GAAA,CAACkC,EAAAA,EAAAA;AACC,4CAAA,QAAA,gBAAAlC,GAAA,CAACmC,UAAAA,EAAAA;gDAAWhB,OAAAA,EAAQ,OAAA;0DACjB1D,aAAAA,CAAc;oDACb0B,EAAAA,EAAI,gCAAA;oDACJC,cAAAA,EAAgB;AAClB,iDAAA;;;sDAGJY,GAAA,CAACkC,EAAAA,EAAAA;AACC,4CAAA,QAAA,gBAAAlC,GAAA,CAACmC,UAAAA,EAAAA;gDAAWhB,OAAAA,EAAQ,OAAA;0DACjB1D,aAAAA,CAAc;oDAAE0B,EAAAA,EAAI,2BAAA;oDAA6BC,cAAAA,EAAgB;AAAU,iDAAA;;;;;;0CAKpFY,GAAA,CAACoC,KAAAA,EAAAA;AACEhE,gCAAAA,QAAAA,EAAAA,QAAAA,CAASiE,GAAG,CAAC,CAAC3C,OAAAA,iBACbU,IAAA,CAAC6B,EAAAA,EAAAA;;0DACCjC,GAAA,CAACsC,EAAAA,EAAAA;AACC,gDAAA,QAAA,gBAAAlC,IAAA,CAACS,IAAAA,EAAAA;oDAAKC,GAAAA,EAAK,CAAA;;sEACTd,GAAA,CAACmC,UAAAA,EAAAA;4DAAWI,SAAAA,EAAU,YAAA;AACnB7C,4DAAAA,QAAAA,EAAAA,OAAAA,CAAQ8C,UAAU,KAChB9C,OAAAA,CAAQ+C,QAAQ,GACb/C,OAAAA,CAAQ+C,QAAQ,CAACC,KAAK,CAAC,CAAA,EAAG,KAC1BjF,aAAAA,CAAc;gEACZ0B,EAAAA,EAAI,iCAAA;gEACJC,cAAAA,EAAgB;6DAClB,CAAC;;wDAERM,OAAAA,CAAQC,OAAO,kBACdK,GAAA,CAAC2C,KAAAA,EAAAA;sEACElF,aAAAA,CAAc;gEACb0B,EAAAA,EAAI,2BAAA;gEACJC,cAAAA,EAAgB;AAClB,6DAAA;;;;;0DAKRY,GAAA,CAACsC,EAAAA,EAAAA;AACC,gDAAA,QAAA,gBAAAtC,GAAA,CAACmC,UAAAA,EAAAA;oDAAWI,SAAAA,EAAU,YAAA;8DACnB7C,OAAAA,CAAQkD,OAAO,iBACd5C,GAAA,CAAC6C,YAAAA,EAAAA;wDAAaC,SAAAA,EAAW,IAAIC,IAAAA,CAAKrD,OAAAA,CAAQkD,OAAO;AAEjD,qDAAA,CAAA,GAAA;;;0DAIN5C,GAAA,CAACsC,EAAAA,EAAAA;AACC,gDAAA,QAAA,gBAAAtC,GAAA,CAACmC,UAAAA,EAAAA;oDAAWI,SAAAA,EAAU,YAAA;8DACnB7C,OAAAA,CAAQsD,YAAY,iBACnBhD,GAAA,CAAC6C,YAAAA,EAAAA;wDAAaC,SAAAA,EAAW,IAAIC,IAAAA,CAAKrD,OAAAA,CAAQsD,YAAY;AAEtD,qDAAA,CAAA,GAAA;;;0DAINhD,GAAA,CAACsC,EAAAA,EAAAA;AACC,gDAAA,QAAA,gBAAAtC,GAAA,CAACa,IAAAA,EAAAA;oDAAKoC,cAAAA,EAAe,KAAA;oDAAMC,OAAAA,EAAS,CAACC,CAAAA,GAAMA,CAAAA,CAAEC,eAAe,EAAA;4EAC1DhD,IAAA,CAACW,OAAOC,IAAI,EAAA;;AACV,0EAAAhB,GAAA,CAACe,OAAOE,OAAO,EAAA;AACb,gEAAA,QAAA,gBAAAjB,GAAA,CAACqD,UAAAA,EAAAA;AACCC,oEAAAA,KAAAA,EAAO7F,aAAAA,CAAc;wEACnB0B,EAAAA,EAAI,0BAAA;wEACJC,cAAAA,EAAgB;AAClB,qEAAA,CAAA;oEACA+B,OAAAA,EAAQ,OAAA;AAER,oEAAA,QAAA,gBAAAnB,GAAA,CAACqB,OAAAA,EAAAA,EAAAA;;;0EAGLrB,GAAA,CAACsB,aAAAA,EAAAA;AAAcC,gEAAAA,SAAAA,EAAW,IAAM9B,YAAAA,CAAaC,OAAAA,CAAAA;0EAC1CA,OAAAA,CAAQC,OAAO,GACZlC,aAAAA,CAAc;oEACZ0B,EAAAA,EAAI,yCAAA;oEACJC,cAAAA,EACE;AACJ,iEAAA,CAAA,GACA3B,aAAAA,CAAc;oEACZ0B,EAAAA,EAAI,kCAAA;oEACJC,cAAAA,EACE;AACJ,iEAAA;;;;;;;AAjELM,qCAAAA,EAAAA,OAAAA,CAAQP,EAAE,CAAA;;;;;;;;AA8EnC;;;;"}
|
|
@@ -25,6 +25,11 @@ const renderAdmin = async (mountNode, { plugins, customisations, features })=>{
|
|
|
25
25
|
return features?.future?.[name] === true;
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
|
+
featureFlags: {
|
|
29
|
+
isEnabled: (name)=>{
|
|
30
|
+
return features?.[name] === true;
|
|
31
|
+
}
|
|
32
|
+
},
|
|
28
33
|
// eslint-disable-next-line
|
|
29
34
|
// @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision. Cannot use @ts-expect-error because of build:code and build:types context collision.
|
|
30
35
|
features: {
|
|
@@ -45,7 +50,7 @@ const renderAdmin = async (mountNode, { plugins, customisations, features })=>{
|
|
|
45
50
|
// eslint-disable-next-line
|
|
46
51
|
// @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.
|
|
47
52
|
ai: {
|
|
48
|
-
enabled:
|
|
53
|
+
enabled: false
|
|
49
54
|
}
|
|
50
55
|
};
|
|
51
56
|
const { get } = getFetchClient.getFetchClient();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sources":["../../../../admin/src/render.ts"],"sourcesContent":["/* eslint-disable no-undef */\nimport { createRoot } from 'react-dom/client';\n\nimport { StrapiApp, StrapiAppConstructorArgs } from './StrapiApp';\nimport { getFetchClient } from './utils/getFetchClient';\nimport { getProjectType } from './utils/getProjectType';\nimport { createAbsoluteUrl } from './utils/urls';\n\nimport type { Modules } from '@strapi/types';\n\ninterface RenderAdminArgs {\n customisations: {\n register?: (app: StrapiApp) => Promise<void> | void;\n bootstrap?: (app: StrapiApp) => Promise<void> | void;\n config?: StrapiAppConstructorArgs['config'];\n };\n plugins: StrapiAppConstructorArgs['appPlugins'];\n features?: Modules.Features.FeaturesService['config'];\n}\n\nconst renderAdmin = async (\n mountNode: HTMLElement | null,\n { plugins, customisations, features }: RenderAdminArgs\n) => {\n if (!mountNode) {\n throw new Error('[@strapi/admin]: Could not find the root element to mount the admin app');\n }\n\n window.strapi = {\n /**\n * This ENV variable is passed from the strapi instance, by default no url is set\n * in the config and therefore the instance returns you an empty string so URLs are relative.\n *\n * To ensure that the backendURL is always set, we use the window.location.origin as a fallback.\n */\n backendURL: createAbsoluteUrl(process.env.STRAPI_ADMIN_BACKEND_URL),\n isEE: false,\n isTrial: false,\n telemetryDisabled: process.env.STRAPI_TELEMETRY_DISABLED === 'true',\n future: {\n isEnabled: (name: keyof NonNullable<Modules.Features.FeaturesConfig['future']>) => {\n return features?.future?.[name] === true;\n },\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision. Cannot use @ts-expect-error because of build:code and build:types context collision.\n features: {\n SSO: 'sso',\n AUDIT_LOGS: 'audit-logs',\n REVIEW_WORKFLOWS: 'review-workflows',\n /**\n * If we don't get the license then we know it's not EE\n * so no feature is enabled.\n */\n isEnabled: () => false,\n },\n projectType: 'Community',\n flags: {\n nps: false,\n promoteEE: true,\n docLinks: true,\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.\n ai: {\n enabled:
|
|
1
|
+
{"version":3,"file":"render.js","sources":["../../../../admin/src/render.ts"],"sourcesContent":["/* eslint-disable no-undef */\nimport { createRoot } from 'react-dom/client';\n\nimport { StrapiApp, StrapiAppConstructorArgs } from './StrapiApp';\nimport { getFetchClient } from './utils/getFetchClient';\nimport { getProjectType } from './utils/getProjectType';\nimport { createAbsoluteUrl } from './utils/urls';\n\nimport type { Modules } from '@strapi/types';\n\ninterface RenderAdminArgs {\n customisations: {\n register?: (app: StrapiApp) => Promise<void> | void;\n bootstrap?: (app: StrapiApp) => Promise<void> | void;\n config?: StrapiAppConstructorArgs['config'];\n };\n plugins: StrapiAppConstructorArgs['appPlugins'];\n features?: Modules.Features.FeaturesService['config'];\n}\n\nconst renderAdmin = async (\n mountNode: HTMLElement | null,\n { plugins, customisations, features }: RenderAdminArgs\n) => {\n if (!mountNode) {\n throw new Error('[@strapi/admin]: Could not find the root element to mount the admin app');\n }\n\n window.strapi = {\n /**\n * This ENV variable is passed from the strapi instance, by default no url is set\n * in the config and therefore the instance returns you an empty string so URLs are relative.\n *\n * To ensure that the backendURL is always set, we use the window.location.origin as a fallback.\n */\n backendURL: createAbsoluteUrl(process.env.STRAPI_ADMIN_BACKEND_URL),\n isEE: false,\n isTrial: false,\n telemetryDisabled: process.env.STRAPI_TELEMETRY_DISABLED === 'true',\n future: {\n isEnabled: (name: keyof NonNullable<Modules.Features.FeaturesConfig['future']>) => {\n return features?.future?.[name] === true;\n },\n },\n featureFlags: {\n isEnabled: (name: keyof Omit<Modules.Features.FeaturesConfig, 'future'>) => {\n return features?.[name] === true;\n },\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision. Cannot use @ts-expect-error because of build:code and build:types context collision.\n features: {\n SSO: 'sso',\n AUDIT_LOGS: 'audit-logs',\n REVIEW_WORKFLOWS: 'review-workflows',\n /**\n * If we don't get the license then we know it's not EE\n * so no feature is enabled.\n */\n isEnabled: () => false,\n },\n projectType: 'Community',\n flags: {\n nps: false,\n promoteEE: true,\n docLinks: true,\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.\n ai: {\n enabled: false,\n },\n };\n\n const { get } = getFetchClient();\n\n interface ProjectType extends Pick<Window['strapi'], 'flags'> {\n isEE: boolean;\n isTrial: boolean;\n /**\n * The licensed plan price id, sent by the license registry (EE only).\n * Used to distinguish the Growth plan from other Enterprise plans.\n */\n planPriceId?: string;\n features: {\n name: string;\n }[];\n ai: Window['strapi']['ai'];\n }\n\n try {\n const {\n data: {\n data: { isEE, isTrial, features, flags, ai, planPriceId },\n },\n } = await get<{ data: ProjectType }>('/admin/project-type');\n\n window.strapi.isEE = isEE;\n window.strapi.isTrialLicense = isTrial;\n window.strapi.flags = flags;\n window.strapi.features = {\n ...window.strapi.features,\n isEnabled: (featureName: string | undefined) =>\n features.some((feature) => feature.name === featureName),\n };\n window.strapi.projectType = getProjectType({ isEE, planPriceId });\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.\n window.strapi.ai = ai;\n } catch (err) {\n /**\n * If this fails, we simply don't activate any EE features.\n * Should we warn clearer in the UI?\n */\n console.error(err);\n }\n\n const app = new StrapiApp({\n config: customisations?.config,\n appPlugins: plugins,\n });\n\n await app.register(customisations?.register);\n await app.bootstrap(customisations?.bootstrap);\n await app.loadTrads(customisations?.config?.translations);\n\n createRoot(mountNode).render(app.render());\n\n if (\n typeof module !== 'undefined' &&\n module &&\n 'hot' in module &&\n typeof module.hot === 'object' &&\n module.hot !== null &&\n 'accept' in module.hot &&\n typeof module.hot.accept === 'function'\n ) {\n module.hot.accept();\n }\n\n if (typeof import.meta.hot?.accept === 'function') {\n import.meta.hot.accept();\n }\n};\n\nexport { renderAdmin };\nexport type { RenderAdminArgs };\n"],"names":["renderAdmin","mountNode","plugins","customisations","features","Error","window","strapi","backendURL","createAbsoluteUrl","process","env","STRAPI_ADMIN_BACKEND_URL","isEE","isTrial","telemetryDisabled","STRAPI_TELEMETRY_DISABLED","future","isEnabled","name","featureFlags","SSO","AUDIT_LOGS","REVIEW_WORKFLOWS","projectType","flags","nps","promoteEE","docLinks","ai","enabled","get","getFetchClient","data","planPriceId","isTrialLicense","featureName","some","feature","getProjectType","err","console","error","app","StrapiApp","config","appPlugins","register","bootstrap","loadTrads","translations","createRoot","render","module","hot","accept"],"mappings":"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"}
|
|
@@ -23,6 +23,11 @@ const renderAdmin = async (mountNode, { plugins, customisations, features })=>{
|
|
|
23
23
|
return features?.future?.[name] === true;
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
|
+
featureFlags: {
|
|
27
|
+
isEnabled: (name)=>{
|
|
28
|
+
return features?.[name] === true;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
26
31
|
// eslint-disable-next-line
|
|
27
32
|
// @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision. Cannot use @ts-expect-error because of build:code and build:types context collision.
|
|
28
33
|
features: {
|
|
@@ -43,7 +48,7 @@ const renderAdmin = async (mountNode, { plugins, customisations, features })=>{
|
|
|
43
48
|
// eslint-disable-next-line
|
|
44
49
|
// @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.
|
|
45
50
|
ai: {
|
|
46
|
-
enabled:
|
|
51
|
+
enabled: false
|
|
47
52
|
}
|
|
48
53
|
};
|
|
49
54
|
const { get } = getFetchClient();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.mjs","sources":["../../../../admin/src/render.ts"],"sourcesContent":["/* eslint-disable no-undef */\nimport { createRoot } from 'react-dom/client';\n\nimport { StrapiApp, StrapiAppConstructorArgs } from './StrapiApp';\nimport { getFetchClient } from './utils/getFetchClient';\nimport { getProjectType } from './utils/getProjectType';\nimport { createAbsoluteUrl } from './utils/urls';\n\nimport type { Modules } from '@strapi/types';\n\ninterface RenderAdminArgs {\n customisations: {\n register?: (app: StrapiApp) => Promise<void> | void;\n bootstrap?: (app: StrapiApp) => Promise<void> | void;\n config?: StrapiAppConstructorArgs['config'];\n };\n plugins: StrapiAppConstructorArgs['appPlugins'];\n features?: Modules.Features.FeaturesService['config'];\n}\n\nconst renderAdmin = async (\n mountNode: HTMLElement | null,\n { plugins, customisations, features }: RenderAdminArgs\n) => {\n if (!mountNode) {\n throw new Error('[@strapi/admin]: Could not find the root element to mount the admin app');\n }\n\n window.strapi = {\n /**\n * This ENV variable is passed from the strapi instance, by default no url is set\n * in the config and therefore the instance returns you an empty string so URLs are relative.\n *\n * To ensure that the backendURL is always set, we use the window.location.origin as a fallback.\n */\n backendURL: createAbsoluteUrl(process.env.STRAPI_ADMIN_BACKEND_URL),\n isEE: false,\n isTrial: false,\n telemetryDisabled: process.env.STRAPI_TELEMETRY_DISABLED === 'true',\n future: {\n isEnabled: (name: keyof NonNullable<Modules.Features.FeaturesConfig['future']>) => {\n return features?.future?.[name] === true;\n },\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision. Cannot use @ts-expect-error because of build:code and build:types context collision.\n features: {\n SSO: 'sso',\n AUDIT_LOGS: 'audit-logs',\n REVIEW_WORKFLOWS: 'review-workflows',\n /**\n * If we don't get the license then we know it's not EE\n * so no feature is enabled.\n */\n isEnabled: () => false,\n },\n projectType: 'Community',\n flags: {\n nps: false,\n promoteEE: true,\n docLinks: true,\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.\n ai: {\n enabled:
|
|
1
|
+
{"version":3,"file":"render.mjs","sources":["../../../../admin/src/render.ts"],"sourcesContent":["/* eslint-disable no-undef */\nimport { createRoot } from 'react-dom/client';\n\nimport { StrapiApp, StrapiAppConstructorArgs } from './StrapiApp';\nimport { getFetchClient } from './utils/getFetchClient';\nimport { getProjectType } from './utils/getProjectType';\nimport { createAbsoluteUrl } from './utils/urls';\n\nimport type { Modules } from '@strapi/types';\n\ninterface RenderAdminArgs {\n customisations: {\n register?: (app: StrapiApp) => Promise<void> | void;\n bootstrap?: (app: StrapiApp) => Promise<void> | void;\n config?: StrapiAppConstructorArgs['config'];\n };\n plugins: StrapiAppConstructorArgs['appPlugins'];\n features?: Modules.Features.FeaturesService['config'];\n}\n\nconst renderAdmin = async (\n mountNode: HTMLElement | null,\n { plugins, customisations, features }: RenderAdminArgs\n) => {\n if (!mountNode) {\n throw new Error('[@strapi/admin]: Could not find the root element to mount the admin app');\n }\n\n window.strapi = {\n /**\n * This ENV variable is passed from the strapi instance, by default no url is set\n * in the config and therefore the instance returns you an empty string so URLs are relative.\n *\n * To ensure that the backendURL is always set, we use the window.location.origin as a fallback.\n */\n backendURL: createAbsoluteUrl(process.env.STRAPI_ADMIN_BACKEND_URL),\n isEE: false,\n isTrial: false,\n telemetryDisabled: process.env.STRAPI_TELEMETRY_DISABLED === 'true',\n future: {\n isEnabled: (name: keyof NonNullable<Modules.Features.FeaturesConfig['future']>) => {\n return features?.future?.[name] === true;\n },\n },\n featureFlags: {\n isEnabled: (name: keyof Omit<Modules.Features.FeaturesConfig, 'future'>) => {\n return features?.[name] === true;\n },\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision. Cannot use @ts-expect-error because of build:code and build:types context collision.\n features: {\n SSO: 'sso',\n AUDIT_LOGS: 'audit-logs',\n REVIEW_WORKFLOWS: 'review-workflows',\n /**\n * If we don't get the license then we know it's not EE\n * so no feature is enabled.\n */\n isEnabled: () => false,\n },\n projectType: 'Community',\n flags: {\n nps: false,\n promoteEE: true,\n docLinks: true,\n },\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.\n ai: {\n enabled: false,\n },\n };\n\n const { get } = getFetchClient();\n\n interface ProjectType extends Pick<Window['strapi'], 'flags'> {\n isEE: boolean;\n isTrial: boolean;\n /**\n * The licensed plan price id, sent by the license registry (EE only).\n * Used to distinguish the Growth plan from other Enterprise plans.\n */\n planPriceId?: string;\n features: {\n name: string;\n }[];\n ai: Window['strapi']['ai'];\n }\n\n try {\n const {\n data: {\n data: { isEE, isTrial, features, flags, ai, planPriceId },\n },\n } = await get<{ data: ProjectType }>('/admin/project-type');\n\n window.strapi.isEE = isEE;\n window.strapi.isTrialLicense = isTrial;\n window.strapi.flags = flags;\n window.strapi.features = {\n ...window.strapi.features,\n isEnabled: (featureName: string | undefined) =>\n features.some((feature) => feature.name === featureName),\n };\n window.strapi.projectType = getProjectType({ isEE, planPriceId });\n // eslint-disable-next-line\n // @ts-ignore – there's pollution from the global scope of Node. Cannot use @ts-expect-error because of build:code and build:types context collision.\n window.strapi.ai = ai;\n } catch (err) {\n /**\n * If this fails, we simply don't activate any EE features.\n * Should we warn clearer in the UI?\n */\n console.error(err);\n }\n\n const app = new StrapiApp({\n config: customisations?.config,\n appPlugins: plugins,\n });\n\n await app.register(customisations?.register);\n await app.bootstrap(customisations?.bootstrap);\n await app.loadTrads(customisations?.config?.translations);\n\n createRoot(mountNode).render(app.render());\n\n if (\n typeof module !== 'undefined' &&\n module &&\n 'hot' in module &&\n typeof module.hot === 'object' &&\n module.hot !== null &&\n 'accept' in module.hot &&\n typeof module.hot.accept === 'function'\n ) {\n module.hot.accept();\n }\n\n if (typeof import.meta.hot?.accept === 'function') {\n import.meta.hot.accept();\n }\n};\n\nexport { renderAdmin };\nexport type { RenderAdminArgs };\n"],"names":["renderAdmin","mountNode","plugins","customisations","features","Error","window","strapi","backendURL","createAbsoluteUrl","process","env","STRAPI_ADMIN_BACKEND_URL","isEE","isTrial","telemetryDisabled","STRAPI_TELEMETRY_DISABLED","future","isEnabled","name","featureFlags","SSO","AUDIT_LOGS","REVIEW_WORKFLOWS","projectType","flags","nps","promoteEE","docLinks","ai","enabled","get","getFetchClient","data","planPriceId","isTrialLicense","featureName","some","feature","getProjectType","err","console","error","app","StrapiApp","config","appPlugins","register","bootstrap","loadTrads","translations","createRoot","render","module","hot","accept"],"mappings":"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"}
|
|
@@ -210,6 +210,10 @@ var en = {
|
|
|
210
210
|
"Settings.permissions.auditLogs.listview.export.ready.title": "Export ready",
|
|
211
211
|
"Settings.permissions.auditLogs.listview.header.subtitle": "Logs of all the activities that happened in your environment",
|
|
212
212
|
"Settings.permissions.auditLogs.not-available": "Audit Logs is only available as part of a paid plan. Upgrade to get a searchable and filterable display of all activities.",
|
|
213
|
+
"Settings.permissions.auditLogs.locale.create": "Create locale",
|
|
214
|
+
"Settings.permissions.auditLogs.locale.default.update": "Change default locale",
|
|
215
|
+
"Settings.permissions.auditLogs.locale.delete": "Delete locale",
|
|
216
|
+
"Settings.permissions.auditLogs.locale.update": "Update locale",
|
|
213
217
|
"Settings.permissions.auditLogs.media.create": "Create media",
|
|
214
218
|
"Settings.permissions.auditLogs.media.delete": "Delete media",
|
|
215
219
|
"Settings.permissions.auditLogs.media.update": "Update media",
|
|
@@ -228,6 +232,10 @@ var en = {
|
|
|
228
232
|
"Settings.permissions.auditLogs.role.create": "Create role",
|
|
229
233
|
"Settings.permissions.auditLogs.role.delete": "Delete role",
|
|
230
234
|
"Settings.permissions.auditLogs.role.update": "Update role",
|
|
235
|
+
"Settings.permissions.auditLogs.token.create": "Create token",
|
|
236
|
+
"Settings.permissions.auditLogs.token.delete": "Delete token",
|
|
237
|
+
"Settings.permissions.auditLogs.token.regenerate": "Regenerate token",
|
|
238
|
+
"Settings.permissions.auditLogs.token.update": "Update token",
|
|
231
239
|
"Settings.permissions.auditLogs.user": "User",
|
|
232
240
|
"Settings.permissions.auditLogs.user.create": "Create user",
|
|
233
241
|
"Settings.permissions.auditLogs.user.delete": "Delete user",
|
|
@@ -540,6 +548,12 @@ var en = {
|
|
|
540
548
|
"app.components.PluginCard.PopUpWarning.install.impossible.title": "Downloading is impossible",
|
|
541
549
|
"app.components.PluginCard.compatible": "Compatible with your app",
|
|
542
550
|
"app.components.PluginCard.compatibleCommunity": "Compatible with the community",
|
|
551
|
+
"app.components.MediaLibraryBanner.button": "Docs",
|
|
552
|
+
"app.components.MediaLibraryBanner.button.enabled": "Read blog post",
|
|
553
|
+
"app.components.MediaLibraryBanner.close": "Close the banner. ",
|
|
554
|
+
"app.components.MediaLibraryBanner.intro": "Introducing the new Media Library ",
|
|
555
|
+
"app.components.MediaLibraryBanner.text": "Check the documentation to learn how to switch to the new one.",
|
|
556
|
+
"app.components.MediaLibraryBanner.text.enabled": "You're now using the revamped version.",
|
|
543
557
|
"app.components.PluginCard.more-details": "More details",
|
|
544
558
|
"app.components.Select.placeholder": "Select",
|
|
545
559
|
"app.components.ToggleCheckbox.off-label": "False",
|
|
@@ -579,6 +593,8 @@ var en = {
|
|
|
579
593
|
"app.containers.Users.ModalForm.footer.button-success": "Invite user",
|
|
580
594
|
"app.links.configure-view": "Configure the view",
|
|
581
595
|
"app.page.not.found": "Oops! We can't seem to find the page you're looking for...",
|
|
596
|
+
"app.session.ended.title": "Session ended",
|
|
597
|
+
"app.session.ended.unsaved": "Your session has ended and can't be resumed. Your unsaved changes will be lost when you log out.",
|
|
582
598
|
"app.static.links.cheatsheet": "CheatSheet",
|
|
583
599
|
"app.utils.SelectOption.defaultMessage": " ",
|
|
584
600
|
"app.utils.add-filter": "Add filter",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|