@strapi/admin 5.56.0 → 5.57.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/components/Filters.js +1 -1
- package/dist/admin/admin/src/components/Filters.js.map +1 -1
- package/dist/admin/admin/src/components/Filters.mjs +1 -1
- package/dist/admin/admin/src/components/Filters.mjs.map +1 -1
- package/dist/admin/admin/src/components/FormInputs/Enumeration.js +2 -2
- package/dist/admin/admin/src/components/FormInputs/Enumeration.js.map +1 -1
- package/dist/admin/admin/src/components/FormInputs/Enumeration.mjs +2 -2
- package/dist/admin/admin/src/components/FormInputs/Enumeration.mjs.map +1 -1
- package/dist/admin/admin/src/components/MediaLibraryBanner.js +38 -2
- package/dist/admin/admin/src/components/MediaLibraryBanner.js.map +1 -1
- package/dist/admin/admin/src/components/MediaLibraryBanner.mjs +18 -2
- package/dist/admin/admin/src/components/MediaLibraryBanner.mjs.map +1 -1
- package/dist/admin/admin/src/components/RelativeTime.js +9 -0
- package/dist/admin/admin/src/components/RelativeTime.js.map +1 -1
- package/dist/admin/admin/src/components/RelativeTime.mjs +10 -1
- package/dist/admin/admin/src/components/RelativeTime.mjs.map +1 -1
- package/dist/admin/admin/src/components/TopBanners.js +52 -0
- package/dist/admin/admin/src/components/TopBanners.js.map +1 -0
- package/dist/admin/admin/src/components/TopBanners.mjs +30 -0
- package/dist/admin/admin/src/components/TopBanners.mjs.map +1 -0
- package/dist/admin/admin/src/features/Tracking.js +28 -8
- package/dist/admin/admin/src/features/Tracking.js.map +1 -1
- package/dist/admin/admin/src/features/Tracking.mjs +29 -10
- package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.js +4 -20
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.js.map +1 -1
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs +4 -20
- package/dist/admin/admin/src/layouts/AuthenticatedLayout.mjs.map +1 -1
- package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.js +59 -0
- package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.js.map +1 -0
- package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.mjs +37 -0
- package/dist/admin/admin/src/layouts/useAuthenticatedAccessTracking.mjs.map +1 -0
- package/dist/admin/admin/src/translations/en.json.js +5 -0
- package/dist/admin/admin/src/translations/en.json.js.map +1 -1
- package/dist/admin/admin/src/translations/en.json.mjs +5 -0
- package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
- package/dist/admin/admin/src/utils/getFetchClient.js +3 -3
- package/dist/admin/admin/src/utils/getFetchClient.js.map +1 -1
- package/dist/admin/admin/src/utils/getFetchClient.mjs +2 -2
- package/dist/admin/admin/src/utils/getFetchClient.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js +6 -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 +6 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs.map +1 -1
- package/dist/admin/src/components/MediaLibraryBanner.d.ts +10 -1
- package/dist/admin/src/components/TopBanners.d.ts +8 -0
- package/dist/admin/src/features/Tracking.d.ts +12 -1
- package/dist/admin/src/layouts/useAuthenticatedAccessTracking.d.ts +6 -0
- package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.d.ts +5 -0
- package/dist/ee/server/src/controllers/admin.d.ts.map +1 -1
- package/dist/ee/server/src/controllers/authentication-utils/utils.d.ts +8 -2
- package/dist/ee/server/src/controllers/authentication-utils/utils.d.ts.map +1 -1
- package/dist/ee/server/src/controllers/authentication.d.ts.map +1 -1
- package/dist/ee/server/src/controllers/user.d.ts.map +1 -1
- package/dist/ee/server/src/index.d.ts +4 -1
- package/dist/ee/server/src/index.d.ts.map +1 -1
- package/dist/ee/server/src/services/index.d.ts +4 -1
- package/dist/ee/server/src/services/index.d.ts.map +1 -1
- package/dist/ee/server/src/services/metrics.d.ts.map +1 -1
- package/dist/ee/server/src/services/persist-tables.d.ts.map +1 -1
- package/dist/ee/server/src/services/seat-enforcement.d.ts +3 -1
- package/dist/ee/server/src/services/seat-enforcement.d.ts.map +1 -1
- package/dist/server/ee/server/src/controllers/admin.js +3 -4
- package/dist/server/ee/server/src/controllers/admin.js.map +1 -1
- package/dist/server/ee/server/src/controllers/admin.mjs +3 -4
- package/dist/server/ee/server/src/controllers/admin.mjs.map +1 -1
- package/dist/server/ee/server/src/controllers/authentication-utils/utils.js +2 -2
- package/dist/server/ee/server/src/controllers/authentication-utils/utils.js.map +1 -1
- package/dist/server/ee/server/src/controllers/authentication-utils/utils.mjs +2 -2
- package/dist/server/ee/server/src/controllers/authentication-utils/utils.mjs.map +1 -1
- package/dist/server/ee/server/src/controllers/authentication.js +11 -11
- package/dist/server/ee/server/src/controllers/authentication.js.map +1 -1
- package/dist/server/ee/server/src/controllers/authentication.mjs +11 -11
- package/dist/server/ee/server/src/controllers/authentication.mjs.map +1 -1
- package/dist/server/ee/server/src/controllers/user.js +7 -8
- package/dist/server/ee/server/src/controllers/user.js.map +1 -1
- package/dist/server/ee/server/src/controllers/user.mjs +8 -9
- package/dist/server/ee/server/src/controllers/user.mjs.map +1 -1
- package/dist/server/ee/server/src/services/metrics.js +9 -7
- package/dist/server/ee/server/src/services/metrics.js.map +1 -1
- package/dist/server/ee/server/src/services/metrics.mjs +9 -7
- package/dist/server/ee/server/src/services/metrics.mjs.map +1 -1
- package/dist/server/ee/server/src/services/persist-tables.js +3 -4
- package/dist/server/ee/server/src/services/persist-tables.js.map +1 -1
- package/dist/server/ee/server/src/services/persist-tables.mjs +3 -4
- package/dist/server/ee/server/src/services/persist-tables.mjs.map +1 -1
- package/dist/server/ee/server/src/services/role.js +2 -2
- package/dist/server/ee/server/src/services/role.js.map +1 -1
- package/dist/server/ee/server/src/services/role.mjs +1 -1
- package/dist/server/ee/server/src/services/role.mjs.map +1 -1
- package/dist/server/ee/server/src/services/seat-enforcement.js +20 -20
- package/dist/server/ee/server/src/services/seat-enforcement.js.map +1 -1
- package/dist/server/ee/server/src/services/seat-enforcement.mjs +20 -20
- package/dist/server/ee/server/src/services/seat-enforcement.mjs.map +1 -1
- package/dist/server/ee/server/src/services/user.js +1 -2
- package/dist/server/ee/server/src/services/user.js.map +1 -1
- package/dist/server/ee/server/src/services/user.mjs +2 -3
- package/dist/server/ee/server/src/services/user.mjs.map +1 -1
- package/dist/server/ee/server/src/utils/sso-lock.js +2 -2
- package/dist/server/ee/server/src/utils/sso-lock.js.map +1 -1
- package/dist/server/ee/server/src/utils/sso-lock.mjs +1 -1
- package/dist/server/ee/server/src/utils/sso-lock.mjs.map +1 -1
- package/dist/server/server/src/audit-logs/admin-users.js +3 -3
- package/dist/server/server/src/audit-logs/admin-users.js.map +1 -1
- package/dist/server/server/src/audit-logs/admin-users.mjs +2 -2
- package/dist/server/server/src/audit-logs/admin-users.mjs.map +1 -1
- package/dist/server/server/src/audit-logs/tokens.js +3 -3
- package/dist/server/server/src/audit-logs/tokens.js.map +1 -1
- package/dist/server/server/src/audit-logs/tokens.mjs +2 -2
- package/dist/server/server/src/audit-logs/tokens.mjs.map +1 -1
- package/dist/server/server/src/audit-logs/webhooks.js +2 -2
- package/dist/server/server/src/audit-logs/webhooks.js.map +1 -1
- package/dist/server/server/src/audit-logs/webhooks.mjs +1 -1
- package/dist/server/server/src/audit-logs/webhooks.mjs.map +1 -1
- package/dist/server/server/src/bootstrap.js +6 -4
- package/dist/server/server/src/bootstrap.js.map +1 -1
- package/dist/server/server/src/bootstrap.mjs +6 -4
- package/dist/server/server/src/bootstrap.mjs.map +1 -1
- package/dist/server/server/src/controllers/admin-token.js +8 -8
- package/dist/server/server/src/controllers/admin-token.js.map +1 -1
- package/dist/server/server/src/controllers/admin-token.mjs +4 -4
- package/dist/server/server/src/controllers/admin-token.mjs.map +1 -1
- package/dist/server/server/src/controllers/admin.js +3 -5
- package/dist/server/server/src/controllers/admin.js.map +1 -1
- package/dist/server/server/src/controllers/admin.mjs +2 -4
- package/dist/server/server/src/controllers/admin.mjs.map +1 -1
- package/dist/server/server/src/controllers/api-token.js +8 -8
- package/dist/server/server/src/controllers/api-token.js.map +1 -1
- package/dist/server/server/src/controllers/api-token.mjs +4 -4
- package/dist/server/server/src/controllers/api-token.mjs.map +1 -1
- package/dist/server/server/src/controllers/formatters/conditions.js +2 -2
- package/dist/server/server/src/controllers/formatters/conditions.js.map +1 -1
- package/dist/server/server/src/controllers/formatters/conditions.mjs +2 -2
- package/dist/server/server/src/controllers/formatters/conditions.mjs.map +1 -1
- package/dist/server/server/src/controllers/transfer/index.js +2 -2
- package/dist/server/server/src/controllers/transfer/index.js.map +1 -1
- package/dist/server/server/src/controllers/transfer/index.mjs +2 -2
- package/dist/server/server/src/controllers/transfer/index.mjs.map +1 -1
- package/dist/server/server/src/controllers/transfer/token.js +8 -8
- package/dist/server/server/src/controllers/transfer/token.js.map +1 -1
- package/dist/server/server/src/controllers/transfer/token.mjs +4 -4
- package/dist/server/server/src/controllers/transfer/token.mjs.map +1 -1
- package/dist/server/server/src/domain/action/index.js +18 -16
- package/dist/server/server/src/domain/action/index.js.map +1 -1
- package/dist/server/server/src/domain/action/index.mjs +16 -14
- package/dist/server/server/src/domain/action/index.mjs.map +1 -1
- package/dist/server/server/src/domain/action/provider.mjs +4 -4
- package/dist/server/server/src/domain/action/provider.mjs.map +1 -1
- package/dist/server/server/src/domain/condition/index.js +7 -4
- package/dist/server/server/src/domain/condition/index.js.map +1 -1
- package/dist/server/server/src/domain/condition/index.mjs +7 -4
- package/dist/server/server/src/domain/condition/index.mjs.map +1 -1
- package/dist/server/server/src/domain/permission/index.js +24 -15
- package/dist/server/server/src/domain/permission/index.js.map +1 -1
- package/dist/server/server/src/domain/permission/index.mjs +21 -12
- package/dist/server/server/src/domain/permission/index.mjs.map +1 -1
- package/dist/server/server/src/middlewares/rateLimit.js +5 -5
- package/dist/server/server/src/middlewares/rateLimit.js.map +1 -1
- package/dist/server/server/src/middlewares/rateLimit.mjs +4 -4
- package/dist/server/server/src/middlewares/rateLimit.mjs.map +1 -1
- package/dist/server/server/src/register.js +6 -0
- package/dist/server/server/src/register.js.map +1 -1
- package/dist/server/server/src/register.mjs +6 -0
- package/dist/server/server/src/register.mjs.map +1 -1
- package/dist/server/server/src/services/action.js +1 -2
- package/dist/server/server/src/services/action.js.map +1 -1
- package/dist/server/server/src/services/action.mjs +1 -2
- package/dist/server/server/src/services/action.mjs.map +1 -1
- package/dist/server/server/src/services/api-token.js +61 -49
- package/dist/server/server/src/services/api-token.js.map +1 -1
- package/dist/server/server/src/services/api-token.mjs +53 -41
- package/dist/server/server/src/services/api-token.mjs.map +1 -1
- package/dist/server/server/src/services/condition.js +2 -2
- package/dist/server/server/src/services/condition.js.map +1 -1
- package/dist/server/server/src/services/condition.mjs +1 -1
- package/dist/server/server/src/services/condition.mjs.map +1 -1
- package/dist/server/server/src/services/content-type.js +5 -4
- package/dist/server/server/src/services/content-type.js.map +1 -1
- package/dist/server/server/src/services/content-type.mjs +8 -7
- package/dist/server/server/src/services/content-type.mjs.map +1 -1
- package/dist/server/server/src/services/homepage.js +2 -1
- package/dist/server/server/src/services/homepage.js.map +1 -1
- package/dist/server/server/src/services/homepage.mjs +2 -1
- package/dist/server/server/src/services/homepage.mjs.map +1 -1
- package/dist/server/server/src/services/passport/local-strategy.js +2 -2
- package/dist/server/server/src/services/passport/local-strategy.js.map +1 -1
- package/dist/server/server/src/services/passport/local-strategy.mjs +1 -1
- package/dist/server/server/src/services/passport/local-strategy.mjs.map +1 -1
- package/dist/server/server/src/services/passport.js +1 -2
- package/dist/server/server/src/services/passport.js.map +1 -1
- package/dist/server/server/src/services/passport.mjs +1 -2
- package/dist/server/server/src/services/passport.mjs.map +1 -1
- package/dist/server/server/src/services/permission/engine.js +4 -4
- package/dist/server/server/src/services/permission/engine.js.map +1 -1
- package/dist/server/server/src/services/permission/engine.mjs +2 -2
- package/dist/server/server/src/services/permission/engine.mjs.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/index.js +2 -3
- package/dist/server/server/src/services/permission/permissions-manager/index.js.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/index.mjs +1 -2
- package/dist/server/server/src/services/permission/permissions-manager/index.mjs.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/permission-fields.js +6 -6
- package/dist/server/server/src/services/permission/permissions-manager/permission-fields.js.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/permission-fields.mjs +4 -4
- package/dist/server/server/src/services/permission/permissions-manager/permission-fields.mjs.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/sanitize.js +47 -41
- package/dist/server/server/src/services/permission/permissions-manager/sanitize.js.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/sanitize.mjs +44 -38
- package/dist/server/server/src/services/permission/permissions-manager/sanitize.mjs.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/validate.js +30 -26
- package/dist/server/server/src/services/permission/permissions-manager/validate.js.map +1 -1
- package/dist/server/server/src/services/permission/permissions-manager/validate.mjs +28 -24
- package/dist/server/server/src/services/permission/permissions-manager/validate.mjs.map +1 -1
- package/dist/server/server/src/services/permission/queries.js +9 -9
- package/dist/server/server/src/services/permission/queries.js.map +1 -1
- package/dist/server/server/src/services/permission/queries.mjs +9 -9
- package/dist/server/server/src/services/permission/queries.mjs.map +1 -1
- package/dist/server/server/src/services/permission/rename-fields.js +118 -0
- package/dist/server/server/src/services/permission/rename-fields.js.map +1 -0
- package/dist/server/server/src/services/permission/rename-fields.mjs +116 -0
- package/dist/server/server/src/services/permission/rename-fields.mjs.map +1 -0
- package/dist/server/server/src/services/permission/sections-builder/index.js +2 -2
- package/dist/server/server/src/services/permission/sections-builder/index.js.map +1 -1
- package/dist/server/server/src/services/permission/sections-builder/index.mjs +2 -2
- package/dist/server/server/src/services/permission/sections-builder/index.mjs.map +1 -1
- package/dist/server/server/src/services/permission/sections-builder/section.js +1 -2
- package/dist/server/server/src/services/permission/sections-builder/section.js.map +1 -1
- package/dist/server/server/src/services/permission/sections-builder/section.mjs +1 -2
- package/dist/server/server/src/services/permission/sections-builder/section.mjs.map +1 -1
- package/dist/server/server/src/services/permission/sections-builder/utils.js +6 -6
- package/dist/server/server/src/services/permission/sections-builder/utils.js.map +1 -1
- package/dist/server/server/src/services/permission/sections-builder/utils.mjs +4 -4
- package/dist/server/server/src/services/permission/sections-builder/utils.mjs.map +1 -1
- package/dist/server/server/src/services/role.js +20 -19
- package/dist/server/server/src/services/role.js.map +1 -1
- package/dist/server/server/src/services/role.mjs +20 -19
- package/dist/server/server/src/services/role.mjs.map +1 -1
- package/dist/server/server/src/services/transfer/token.js +20 -16
- package/dist/server/server/src/services/transfer/token.js.map +1 -1
- package/dist/server/server/src/services/transfer/token.mjs +14 -10
- package/dist/server/server/src/services/transfer/token.mjs.map +1 -1
- package/dist/server/server/src/services/user.js +2 -3
- package/dist/server/server/src/services/user.js.map +1 -1
- package/dist/server/server/src/services/user.mjs +3 -4
- package/dist/server/server/src/services/user.mjs.map +1 -1
- package/dist/server/server/src/strategies/api-token-utils.js +2 -3
- package/dist/server/server/src/strategies/api-token-utils.js.map +1 -1
- package/dist/server/server/src/strategies/api-token-utils.mjs +2 -3
- package/dist/server/server/src/strategies/api-token-utils.mjs.map +1 -1
- package/dist/server/server/src/strategies/content-api-token.js +3 -3
- package/dist/server/server/src/strategies/content-api-token.js.map +1 -1
- package/dist/server/server/src/strategies/content-api-token.mjs +1 -1
- package/dist/server/server/src/strategies/content-api-token.mjs.map +1 -1
- package/dist/server/server/src/strategies/data-transfer.js +4 -4
- package/dist/server/server/src/strategies/data-transfer.js.map +1 -1
- package/dist/server/server/src/strategies/data-transfer.mjs +3 -3
- package/dist/server/server/src/strategies/data-transfer.mjs.map +1 -1
- package/dist/server/server/src/validation/common-validators.js +9 -10
- package/dist/server/server/src/validation/common-validators.js.map +1 -1
- package/dist/server/server/src/validation/common-validators.mjs +13 -14
- package/dist/server/server/src/validation/common-validators.mjs.map +1 -1
- package/dist/server/server/src/validation/user.js +1 -2
- package/dist/server/server/src/validation/user.js.map +1 -1
- package/dist/server/server/src/validation/user.mjs +1 -2
- package/dist/server/server/src/validation/user.mjs.map +1 -1
- package/dist/server/src/audit-logs/tokens.d.ts.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-token.d.ts.map +1 -1
- package/dist/server/src/controllers/admin.d.ts.map +1 -1
- package/dist/server/src/controllers/api-token.d.ts.map +1 -1
- package/dist/server/src/controllers/formatters/conditions.d.ts +1 -1
- package/dist/server/src/controllers/formatters/conditions.d.ts.map +1 -1
- package/dist/server/src/controllers/homepage.d.ts +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -1
- package/dist/server/src/controllers/transfer/index.d.ts.map +1 -1
- package/dist/server/src/controllers/transfer/token.d.ts.map +1 -1
- package/dist/server/src/domain/action/index.d.ts +1 -0
- package/dist/server/src/domain/action/index.d.ts.map +1 -1
- package/dist/server/src/domain/condition/index.d.ts +2 -2
- package/dist/server/src/domain/condition/index.d.ts.map +1 -1
- package/dist/server/src/domain/permission/index.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -3
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/middlewares/index.d.ts.map +1 -1
- package/dist/server/src/middlewares/rateLimit.d.ts.map +1 -1
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/services/action.d.ts.map +1 -1
- package/dist/server/src/services/api-token.d.ts.map +1 -1
- package/dist/server/src/services/condition.d.ts.map +1 -1
- package/dist/server/src/services/content-type.d.ts.map +1 -1
- package/dist/server/src/services/homepage.d.ts +1 -1
- package/dist/server/src/services/homepage.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +2 -2
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/passport/local-strategy.d.ts.map +1 -1
- package/dist/server/src/services/passport.d.ts.map +1 -1
- package/dist/server/src/services/permission/engine.d.ts.map +1 -1
- package/dist/server/src/services/permission/permissions-manager/permission-fields.d.ts.map +1 -1
- package/dist/server/src/services/permission/permissions-manager/sanitize.d.ts.map +1 -1
- package/dist/server/src/services/permission/permissions-manager/validate.d.ts.map +1 -1
- package/dist/server/src/services/permission/queries.d.ts.map +1 -1
- package/dist/server/src/services/permission/rename-fields.d.ts +21 -0
- package/dist/server/src/services/permission/rename-fields.d.ts.map +1 -0
- package/dist/server/src/services/permission/sections-builder/section.d.ts.map +1 -1
- package/dist/server/src/services/permission/sections-builder/utils.d.ts +1 -1
- package/dist/server/src/services/permission/sections-builder/utils.d.ts.map +1 -1
- package/dist/server/src/services/role.d.ts +1 -1
- package/dist/server/src/services/role.d.ts.map +1 -1
- package/dist/server/src/services/transfer/token.d.ts.map +1 -1
- package/dist/server/src/strategies/content-api-token.d.ts.map +1 -1
- package/dist/server/src/validation/user.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaLibraryBanner.mjs","sources":["../../../../../admin/src/components/MediaLibraryBanner.tsx"],"sourcesContent":["import { LinkButton, Typography } from '@strapi/design-system';\nimport { ExternalLink } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\n\nimport { useScopedPersistentState } from '../hooks/usePersistentState';\n\nimport { DismissibleBanner } from './DismissibleBanner';\n\nconst Banner = ({\n isLegacyMediaLibrary,\n onDismiss,\n}: {\n isLegacyMediaLibrary: boolean;\n onDismiss: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n return (\n <DismissibleBanner\n onDismiss={onDismiss}\n closeLabel={formatMessage({\n id: 'app.components.MediaLibraryBanner.close',\n defaultMessage: 'Close',\n })}\n message={\n <>\n <Typography\n variant=\"delta\"\n fontWeight=\"bold\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n fontSize={2}\n >\n {formatMessage({\n id: 'app.components.MediaLibraryBanner.intro',\n defaultMessage: 'Introducing the new Media Library ',\n })}\n </Typography>\n <Typography\n variant=\"delta\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n paddingRight={4}\n fontSize={2}\n >\n {formatMessage(\n isLegacyMediaLibrary\n ? {\n id: 'app.components.MediaLibraryBanner.text',\n defaultMessage:\n 'Check the documentation to learn how to switch to the new one.',\n }\n : {\n id: 'app.components.MediaLibraryBanner.text.enabled',\n defaultMessage: \"You're now using the revamped version.\",\n }\n )}\n </Typography>\n </>\n }\n action={\n isLegacyMediaLibrary ? (\n <LinkButton\n width=\"max-content\"\n variant=\"tertiary\"\n startIcon={<ExternalLink />}\n href=\"https://docs.strapi.io/cms/features/media-library\"\n target=\"_blank\"\n >\n {formatMessage({\n id: 'app.components.MediaLibraryBanner.button',\n defaultMessage: 'Docs',\n })}\n </LinkButton>\n ) : (\n <LinkButton\n width=\"max-content\"\n variant=\"tertiary\"\n href=\"https://strapi.io/blog/strapi-release-roundup-everything-that-changed-between-june-and-august-2026\"\n target=\"_blank\"\n >\n {formatMessage({\n id: 'app.components.MediaLibraryBanner.button.enabled',\n defaultMessage: 'Read blog post',\n })}\n </LinkButton>\n )\n }\n />\n );\n};\n\nconst MediaLibraryBanner = () => {\n const isLegacyMediaLibrary = window.strapi.featureFlags.isEnabled('useLegacyMediaLibrary');\n\n // The flag state is part of the key (not the stored value) so dismissing one\n // message never collides with the other, and toggling `useLegacyMediaLibrary`\n // (enabling it, or rolling it back) brings the banner back with the right message.\n const [isDismissed, setIsDismissed] = useScopedPersistentState<boolean>(\n `STRAPI_MEDIA_LIBRARY_BANNER_DISMISSED_FOR_${isLegacyMediaLibrary}`,\n false\n );\n\n
|
|
1
|
+
{"version":3,"file":"MediaLibraryBanner.mjs","sources":["../../../../../admin/src/components/MediaLibraryBanner.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { LinkButton, Typography } from '@strapi/design-system';\nimport { ExternalLink } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { useMatch } from 'react-router-dom';\n\nimport { useScopedPersistentState } from '../hooks/usePersistentState';\n\nimport { DismissibleBanner } from './DismissibleBanner';\n\nconst Banner = ({\n isLegacyMediaLibrary,\n onDismiss,\n}: {\n isLegacyMediaLibrary: boolean;\n onDismiss: () => void;\n}) => {\n const { formatMessage } = useIntl();\n\n return (\n <DismissibleBanner\n onDismiss={onDismiss}\n closeLabel={formatMessage({\n id: 'app.components.MediaLibraryBanner.close',\n defaultMessage: 'Close',\n })}\n message={\n <>\n <Typography\n variant=\"delta\"\n fontWeight=\"bold\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n fontSize={2}\n >\n {formatMessage({\n id: 'app.components.MediaLibraryBanner.intro',\n defaultMessage: 'Introducing the new Media Library ',\n })}\n </Typography>\n <Typography\n variant=\"delta\"\n textColor=\"neutral0\"\n textAlign=\"center\"\n paddingRight={4}\n fontSize={2}\n >\n {formatMessage(\n isLegacyMediaLibrary\n ? {\n id: 'app.components.MediaLibraryBanner.text',\n defaultMessage:\n 'Check the documentation to learn how to switch to the new one.',\n }\n : {\n id: 'app.components.MediaLibraryBanner.text.enabled',\n defaultMessage: \"You're now using the revamped version.\",\n }\n )}\n </Typography>\n </>\n }\n action={\n isLegacyMediaLibrary ? (\n <LinkButton\n width=\"max-content\"\n variant=\"tertiary\"\n startIcon={<ExternalLink />}\n href=\"https://docs.strapi.io/cms/features/media-library\"\n target=\"_blank\"\n >\n {formatMessage({\n id: 'app.components.MediaLibraryBanner.button',\n defaultMessage: 'Docs',\n })}\n </LinkButton>\n ) : (\n <LinkButton\n width=\"max-content\"\n variant=\"tertiary\"\n href=\"https://strapi.io/blog/strapi-release-roundup-everything-that-changed-between-june-and-august-2026\"\n target=\"_blank\"\n >\n {formatMessage({\n id: 'app.components.MediaLibraryBanner.button.enabled',\n defaultMessage: 'Read blog post',\n })}\n </LinkButton>\n )\n }\n />\n );\n};\n\ninterface MediaLibraryBannerProps {\n /**\n * Called synchronously (before paint) whenever this banner's own visibility changes, so a\n * parent rendering it alongside another banner (e.g. `UpsellBanner`) can hide that other one\n * instead of stacking both. This banner owns its dismissal state, so it's the source of truth\n * for whether it's showing — the parent shouldn't have to re-derive that itself.\n */\n onVisibilityChange?: (isVisible: boolean) => void;\n}\n\nconst MediaLibraryBanner = ({ onVisibilityChange }: MediaLibraryBannerProps = {}) => {\n const isLegacyMediaLibrary = window.strapi.featureFlags.isEnabled('useLegacyMediaLibrary');\n\n // The flag state is part of the key (not the stored value) so dismissing one\n // message never collides with the other, and toggling `useLegacyMediaLibrary`\n // (enabling it, or rolling it back) brings the banner back with the right message.\n const [isDismissed, setIsDismissed] = useScopedPersistentState<boolean>(\n `STRAPI_MEDIA_LIBRARY_BANNER_DISMISSED_FOR_${isLegacyMediaLibrary}`,\n false\n );\n\n // `AuthenticatedLayout` renders this banner on every admin page, but it's only\n // relevant on the Media Library itself (both the new and legacy `upload` plugin\n // route share the same `plugins/upload` mount point).\n const isOnMediaLibraryPage = useMatch('/plugins/upload/*') !== null;\n\n const isVisible = isOnMediaLibraryPage && !isDismissed;\n\n // useLayoutEffect (not useEffect) so the parent's re-render from this lands before the\n // browser paints — otherwise a possibly-visible `UpsellBanner` would flash on screen for a\n // frame before being hidden.\n React.useLayoutEffect(() => {\n onVisibilityChange?.(isVisible);\n }, [isVisible, onVisibilityChange]);\n\n if (!isVisible) {\n return null;\n }\n\n return (\n <Banner isLegacyMediaLibrary={isLegacyMediaLibrary} onDismiss={() => setIsDismissed(true)} />\n );\n};\n\nexport { MediaLibraryBanner };\n"],"names":["Banner","isLegacyMediaLibrary","onDismiss","formatMessage","useIntl","_jsx","DismissibleBanner","closeLabel","id","defaultMessage","message","_jsxs","_Fragment","Typography","variant","fontWeight","textColor","textAlign","fontSize","paddingRight","action","LinkButton","width","startIcon","ExternalLink","href","target","MediaLibraryBanner","onVisibilityChange","window","strapi","featureFlags","isEnabled","isDismissed","setIsDismissed","useScopedPersistentState","isOnMediaLibraryPage","useMatch","isVisible","React","useLayoutEffect"],"mappings":";;;;;;;;;AAWA,MAAMA,SAAS,CAAC,EACdC,oBAAoB,EACpBC,SAAS,EAIV,GAAA;IACC,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAE1B,IAAA,qBACEC,GAAA,CAACC,iBAAAA,EAAAA;QACCJ,SAAAA,EAAWA,SAAAA;AACXK,QAAAA,UAAAA,EAAYJ,aAAAA,CAAc;YACxBK,EAAAA,EAAI,yCAAA;YACJC,cAAAA,EAAgB;AAClB,SAAA,CAAA;QACAC,OAAAA,gBACEC,IAAA,CAAAC,QAAA,EAAA;;8BACEP,GAAA,CAACQ,UAAAA,EAAAA;oBACCC,OAAAA,EAAQ,OAAA;oBACRC,UAAAA,EAAW,MAAA;oBACXC,SAAAA,EAAU,UAAA;oBACVC,SAAAA,EAAU,QAAA;oBACVC,QAAAA,EAAU,CAAA;8BAETf,aAAAA,CAAc;wBACbK,EAAAA,EAAI,yCAAA;wBACJC,cAAAA,EAAgB;AAClB,qBAAA;;8BAEFJ,GAAA,CAACQ,UAAAA,EAAAA;oBACCC,OAAAA,EAAQ,OAAA;oBACRE,SAAAA,EAAU,UAAA;oBACVC,SAAAA,EAAU,QAAA;oBACVE,YAAAA,EAAc,CAAA;oBACdD,QAAAA,EAAU,CAAA;AAETf,oBAAAA,QAAAA,EAAAA,aAAAA,CACCF,oBAAAA,GACI;wBACEO,EAAAA,EAAI,wCAAA;wBACJC,cAAAA,EACE;qBACJ,GACA;wBACED,EAAAA,EAAI,gDAAA;wBACJC,cAAAA,EAAgB;AAClB,qBAAA;;;;AAKZW,QAAAA,MAAAA,EACEnB,qCACEI,GAAA,CAACgB,UAAAA,EAAAA;YACCC,KAAAA,EAAM,aAAA;YACNR,OAAAA,EAAQ,UAAA;AACRS,YAAAA,SAAAA,gBAAWlB,GAAA,CAACmB,YAAAA,EAAAA,EAAAA,CAAAA;YACZC,IAAAA,EAAK,mDAAA;YACLC,MAAAA,EAAO,QAAA;sBAENvB,aAAAA,CAAc;gBACbK,EAAAA,EAAI,0CAAA;gBACJC,cAAAA,EAAgB;AAClB,aAAA;2BAGFJ,GAAA,CAACgB,UAAAA,EAAAA;YACCC,KAAAA,EAAM,aAAA;YACNR,OAAAA,EAAQ,UAAA;YACRW,IAAAA,EAAK,oGAAA;YACLC,MAAAA,EAAO,QAAA;sBAENvB,aAAAA,CAAc;gBACbK,EAAAA,EAAI,kDAAA;gBACJC,cAAAA,EAAgB;AAClB,aAAA;;;AAMZ,CAAA;AAYA,MAAMkB,qBAAqB,CAAC,EAAEC,kBAAkB,EAA2B,GAAG,EAAE,GAAA;AAC9E,IAAA,MAAM3B,uBAAuB4B,MAAAA,CAAOC,MAAM,CAACC,YAAY,CAACC,SAAS,CAAC,uBAAA,CAAA;;;;IAKlE,MAAM,CAACC,aAAaC,cAAAA,CAAe,GAAGC,yBACpC,CAAC,0CAA0C,EAAElC,oBAAAA,CAAAA,CAAsB,EACnE,KAAA,CAAA;;;;IAMF,MAAMmC,oBAAAA,GAAuBC,SAAS,mBAAA,CAAA,KAAyB,IAAA;IAE/D,MAAMC,SAAAA,GAAYF,wBAAwB,CAACH,WAAAA;;;;AAK3CM,IAAAA,KAAAA,CAAMC,eAAe,CAAC,IAAA;QACpBZ,kBAAAA,GAAqBU,SAAAA,CAAAA;IACvB,CAAA,EAAG;AAACA,QAAAA,SAAAA;AAAWV,QAAAA;AAAmB,KAAA,CAAA;AAElC,IAAA,IAAI,CAACU,SAAAA,EAAW;QACd,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,qBACEjC,GAAA,CAACL,MAAAA,EAAAA;QAAOC,oBAAAA,EAAsBA,oBAAAA;AAAsBC,QAAAA,SAAAA,EAAW,IAAMgC,cAAAA,CAAe,IAAA;;AAExF;;;;"}
|
|
@@ -48,6 +48,15 @@ const intervals = [
|
|
|
48
48
|
* ```
|
|
49
49
|
*/ const RelativeTime = /*#__PURE__*/ React__namespace.forwardRef(({ timestamp, customIntervals = [], ...restProps }, forwardedRef)=>{
|
|
50
50
|
const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
|
|
51
|
+
// Invalid Date: intervalToDuration throws RangeError (see #27382).
|
|
52
|
+
if (!dateFns.isValid(timestamp)) {
|
|
53
|
+
return /*#__PURE__*/ jsxRuntime.jsx("time", {
|
|
54
|
+
ref: forwardedRef,
|
|
55
|
+
role: "time",
|
|
56
|
+
...restProps,
|
|
57
|
+
children: "-"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
51
60
|
/**
|
|
52
61
|
* TODO: make this auto-update, like a clock.
|
|
53
62
|
*/ const interval = dateFns.intervalToDuration({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelativeTime.js","sources":["../../../../../admin/src/components/RelativeTime.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Duration, intervalToDuration, isPast } from 'date-fns';\nimport { useIntl } from 'react-intl';\n\nconst intervals: Array<keyof Duration> = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];\n\ninterface CustomInterval {\n unit: keyof Duration;\n text: string;\n threshold: number;\n}\n\ninterface RelativeTimeProps extends React.ComponentPropsWithoutRef<'time'> {\n timestamp: Date;\n customIntervals?: CustomInterval[];\n}\n\n/**\n * Displays the relative time between a given timestamp and the current time.\n * You can display a custom message for given time intervals by passing an array of custom intervals.\n *\n * @example\n * ```jsx\n * <caption>Display \"last hour\" if the timestamp is less than an hour ago</caption>\n * <RelativeTime\n * timestamp={new Date('2021-01-01')}\n * customIntervals={[\n * { unit: 'hours', threshold: 1, text: 'last hour' },\n * ]}\n * ```\n */\nconst RelativeTime = React.forwardRef<HTMLTimeElement, RelativeTimeProps>(\n ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {\n const { formatRelativeTime, formatDate, formatTime } = useIntl();\n\n /**\n * TODO: make this auto-update, like a clock.\n */\n const interval = intervalToDuration({\n start: timestamp,\n end: Date.now(),\n // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.\n }) as Required<Duration>;\n\n const unit =\n intervals.find((intervalUnit) => {\n return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);\n }) ?? 'seconds';\n\n const value = interval[unit] ?? 0;\n const relativeTime = isPast(timestamp) ? -value : value;\n\n // Display custom text if interval is less than the threshold\n const customInterval = customIntervals.find(\n (custom) => interval[custom.unit] < custom.threshold\n );\n\n const displayText = customInterval\n ? customInterval.text\n : formatRelativeTime(relativeTime, unit, { numeric: 'auto' });\n\n return (\n <time\n ref={forwardedRef}\n dateTime={timestamp.toISOString()}\n role=\"time\"\n title={`${formatDate(timestamp)} ${formatTime(timestamp)}`}\n {...restProps}\n >\n {displayText}\n </time>\n );\n }\n);\n\nexport { RelativeTime };\nexport type { CustomInterval, RelativeTimeProps };\n"],"names":["intervals","RelativeTime","React","forwardRef","timestamp","customIntervals","restProps","forwardedRef","formatRelativeTime","formatDate","formatTime","useIntl","interval","intervalToDuration","start","end","Date","now","unit","find","intervalUnit","Object","keys","includes","value","relativeTime","isPast","customInterval","custom","threshold","displayText","text","numeric","
|
|
1
|
+
{"version":3,"file":"RelativeTime.js","sources":["../../../../../admin/src/components/RelativeTime.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Duration, intervalToDuration, isPast, isValid } from 'date-fns';\nimport { useIntl } from 'react-intl';\n\nconst intervals: Array<keyof Duration> = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];\n\ninterface CustomInterval {\n unit: keyof Duration;\n text: string;\n threshold: number;\n}\n\ninterface RelativeTimeProps extends React.ComponentPropsWithoutRef<'time'> {\n timestamp: Date;\n customIntervals?: CustomInterval[];\n}\n\n/**\n * Displays the relative time between a given timestamp and the current time.\n * You can display a custom message for given time intervals by passing an array of custom intervals.\n *\n * @example\n * ```jsx\n * <caption>Display \"last hour\" if the timestamp is less than an hour ago</caption>\n * <RelativeTime\n * timestamp={new Date('2021-01-01')}\n * customIntervals={[\n * { unit: 'hours', threshold: 1, text: 'last hour' },\n * ]}\n * ```\n */\nconst RelativeTime = React.forwardRef<HTMLTimeElement, RelativeTimeProps>(\n ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {\n const { formatRelativeTime, formatDate, formatTime } = useIntl();\n\n // Invalid Date: intervalToDuration throws RangeError (see #27382).\n if (!isValid(timestamp)) {\n return (\n <time ref={forwardedRef} role=\"time\" {...restProps}>\n -\n </time>\n );\n }\n\n /**\n * TODO: make this auto-update, like a clock.\n */\n const interval = intervalToDuration({\n start: timestamp,\n end: Date.now(),\n // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.\n }) as Required<Duration>;\n\n const unit =\n intervals.find((intervalUnit) => {\n return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);\n }) ?? 'seconds';\n\n const value = interval[unit] ?? 0;\n const relativeTime = isPast(timestamp) ? -value : value;\n\n // Display custom text if interval is less than the threshold\n const customInterval = customIntervals.find(\n (custom) => interval[custom.unit] < custom.threshold\n );\n\n const displayText = customInterval\n ? customInterval.text\n : formatRelativeTime(relativeTime, unit, { numeric: 'auto' });\n\n return (\n <time\n ref={forwardedRef}\n dateTime={timestamp.toISOString()}\n role=\"time\"\n title={`${formatDate(timestamp)} ${formatTime(timestamp)}`}\n {...restProps}\n >\n {displayText}\n </time>\n );\n }\n);\n\nexport { RelativeTime };\nexport type { CustomInterval, RelativeTimeProps };\n"],"names":["intervals","RelativeTime","React","forwardRef","timestamp","customIntervals","restProps","forwardedRef","formatRelativeTime","formatDate","formatTime","useIntl","isValid","_jsx","time","ref","role","interval","intervalToDuration","start","end","Date","now","unit","find","intervalUnit","Object","keys","includes","value","relativeTime","isPast","customInterval","custom","threshold","displayText","text","numeric","dateTime","toISOString","title"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,MAAMA,SAAAA,GAAmC;AAAC,IAAA,OAAA;AAAS,IAAA,QAAA;AAAU,IAAA,MAAA;AAAQ,IAAA,OAAA;AAAS,IAAA,SAAA;AAAW,IAAA;AAAU,CAAA;AAanG;;;;;;;;;;;;;AAaC,IACD,MAAMC,YAAAA,iBAAeC,gBAAAA,CAAMC,UAAU,CACnC,CAAC,EAAEC,SAAS,EAAEC,eAAAA,GAAkB,EAAE,EAAE,GAAGC,WAAW,EAAEC,YAAAA,GAAAA;AAClD,IAAA,MAAM,EAAEC,kBAAkB,EAAEC,UAAU,EAAEC,UAAU,EAAE,GAAGC,iBAAAA,EAAAA;;IAGvD,IAAI,CAACC,gBAAQR,SAAAA,CAAAA,EAAY;AACvB,QAAA,qBACES,cAAA,CAACC,MAAAA,EAAAA;YAAKC,GAAAA,EAAKR,YAAAA;YAAcS,IAAAA,EAAK,MAAA;AAAQ,YAAA,GAAGV,SAAS;AAAE,YAAA,QAAA,EAAA;;AAIxD,IAAA;AAEA;;QAGA,MAAMW,WAAWC,0BAAAA,CAAmB;QAClCC,KAAAA,EAAOf,SAAAA;AACPgB,QAAAA,GAAAA,EAAKC,KAAKC,GAAG;AAEf,KAAA,CAAA;AAEA,IAAA,MAAMC,IAAAA,GACJvB,SAAAA,CAAUwB,IAAI,CAAC,CAACC,YAAAA,GAAAA;QACd,OAAOR,QAAQ,CAACQ,YAAAA,CAAa,GAAG,CAAA,IAAKC,OAAOC,IAAI,CAACV,QAAAA,CAAAA,CAAUW,QAAQ,CAACH,YAAAA,CAAAA;IACtE,CAAA,CAAA,IAAM,SAAA;AAER,IAAA,MAAMI,KAAAA,GAAQZ,QAAQ,CAACM,IAAAA,CAAK,IAAI,CAAA;AAChC,IAAA,MAAMO,YAAAA,GAAeC,cAAAA,CAAO3B,SAAAA,CAAAA,GAAa,CAACyB,KAAAA,GAAQA,KAAAA;;AAGlD,IAAA,MAAMG,cAAAA,GAAiB3B,eAAAA,CAAgBmB,IAAI,CACzC,CAACS,MAAAA,GAAWhB,QAAQ,CAACgB,MAAAA,CAAOV,IAAI,CAAC,GAAGU,OAAOC,SAAS,CAAA;AAGtD,IAAA,MAAMC,cAAcH,cAAAA,GAChBA,cAAAA,CAAeI,IAAI,GACnB5B,kBAAAA,CAAmBsB,cAAcP,IAAAA,EAAM;QAAEc,OAAAA,EAAS;AAAO,KAAA,CAAA;AAE7D,IAAA,qBACExB,cAAA,CAACC,MAAAA,EAAAA;QACCC,GAAAA,EAAKR,YAAAA;AACL+B,QAAAA,QAAAA,EAAUlC,UAAUmC,WAAW,EAAA;QAC/BvB,IAAAA,EAAK,MAAA;AACLwB,QAAAA,KAAAA,EAAO,GAAG/B,UAAAA,CAAWL,SAAAA,CAAAA,CAAW,CAAC,EAAEM,WAAWN,SAAAA,CAAAA,CAAAA,CAAY;AACzD,QAAA,GAAGE,SAAS;AAEZ6B,QAAAA,QAAAA,EAAAA;;AAGP,CAAA;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { intervalToDuration, isPast } from 'date-fns';
|
|
3
|
+
import { isValid, intervalToDuration, isPast } from 'date-fns';
|
|
4
4
|
import { useIntl } from 'react-intl';
|
|
5
5
|
|
|
6
6
|
const intervals = [
|
|
@@ -26,6 +26,15 @@ const intervals = [
|
|
|
26
26
|
* ```
|
|
27
27
|
*/ const RelativeTime = /*#__PURE__*/ React.forwardRef(({ timestamp, customIntervals = [], ...restProps }, forwardedRef)=>{
|
|
28
28
|
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
|
29
|
+
// Invalid Date: intervalToDuration throws RangeError (see #27382).
|
|
30
|
+
if (!isValid(timestamp)) {
|
|
31
|
+
return /*#__PURE__*/ jsx("time", {
|
|
32
|
+
ref: forwardedRef,
|
|
33
|
+
role: "time",
|
|
34
|
+
...restProps,
|
|
35
|
+
children: "-"
|
|
36
|
+
});
|
|
37
|
+
}
|
|
29
38
|
/**
|
|
30
39
|
* TODO: make this auto-update, like a clock.
|
|
31
40
|
*/ const interval = intervalToDuration({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RelativeTime.mjs","sources":["../../../../../admin/src/components/RelativeTime.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Duration, intervalToDuration, isPast } from 'date-fns';\nimport { useIntl } from 'react-intl';\n\nconst intervals: Array<keyof Duration> = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];\n\ninterface CustomInterval {\n unit: keyof Duration;\n text: string;\n threshold: number;\n}\n\ninterface RelativeTimeProps extends React.ComponentPropsWithoutRef<'time'> {\n timestamp: Date;\n customIntervals?: CustomInterval[];\n}\n\n/**\n * Displays the relative time between a given timestamp and the current time.\n * You can display a custom message for given time intervals by passing an array of custom intervals.\n *\n * @example\n * ```jsx\n * <caption>Display \"last hour\" if the timestamp is less than an hour ago</caption>\n * <RelativeTime\n * timestamp={new Date('2021-01-01')}\n * customIntervals={[\n * { unit: 'hours', threshold: 1, text: 'last hour' },\n * ]}\n * ```\n */\nconst RelativeTime = React.forwardRef<HTMLTimeElement, RelativeTimeProps>(\n ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {\n const { formatRelativeTime, formatDate, formatTime } = useIntl();\n\n /**\n * TODO: make this auto-update, like a clock.\n */\n const interval = intervalToDuration({\n start: timestamp,\n end: Date.now(),\n // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.\n }) as Required<Duration>;\n\n const unit =\n intervals.find((intervalUnit) => {\n return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);\n }) ?? 'seconds';\n\n const value = interval[unit] ?? 0;\n const relativeTime = isPast(timestamp) ? -value : value;\n\n // Display custom text if interval is less than the threshold\n const customInterval = customIntervals.find(\n (custom) => interval[custom.unit] < custom.threshold\n );\n\n const displayText = customInterval\n ? customInterval.text\n : formatRelativeTime(relativeTime, unit, { numeric: 'auto' });\n\n return (\n <time\n ref={forwardedRef}\n dateTime={timestamp.toISOString()}\n role=\"time\"\n title={`${formatDate(timestamp)} ${formatTime(timestamp)}`}\n {...restProps}\n >\n {displayText}\n </time>\n );\n }\n);\n\nexport { RelativeTime };\nexport type { CustomInterval, RelativeTimeProps };\n"],"names":["intervals","RelativeTime","React","forwardRef","timestamp","customIntervals","restProps","forwardedRef","formatRelativeTime","formatDate","formatTime","useIntl","interval","intervalToDuration","start","end","Date","now","unit","find","intervalUnit","Object","keys","includes","value","relativeTime","isPast","customInterval","custom","threshold","displayText","text","numeric","
|
|
1
|
+
{"version":3,"file":"RelativeTime.mjs","sources":["../../../../../admin/src/components/RelativeTime.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Duration, intervalToDuration, isPast, isValid } from 'date-fns';\nimport { useIntl } from 'react-intl';\n\nconst intervals: Array<keyof Duration> = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'];\n\ninterface CustomInterval {\n unit: keyof Duration;\n text: string;\n threshold: number;\n}\n\ninterface RelativeTimeProps extends React.ComponentPropsWithoutRef<'time'> {\n timestamp: Date;\n customIntervals?: CustomInterval[];\n}\n\n/**\n * Displays the relative time between a given timestamp and the current time.\n * You can display a custom message for given time intervals by passing an array of custom intervals.\n *\n * @example\n * ```jsx\n * <caption>Display \"last hour\" if the timestamp is less than an hour ago</caption>\n * <RelativeTime\n * timestamp={new Date('2021-01-01')}\n * customIntervals={[\n * { unit: 'hours', threshold: 1, text: 'last hour' },\n * ]}\n * ```\n */\nconst RelativeTime = React.forwardRef<HTMLTimeElement, RelativeTimeProps>(\n ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {\n const { formatRelativeTime, formatDate, formatTime } = useIntl();\n\n // Invalid Date: intervalToDuration throws RangeError (see #27382).\n if (!isValid(timestamp)) {\n return (\n <time ref={forwardedRef} role=\"time\" {...restProps}>\n -\n </time>\n );\n }\n\n /**\n * TODO: make this auto-update, like a clock.\n */\n const interval = intervalToDuration({\n start: timestamp,\n end: Date.now(),\n // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.\n }) as Required<Duration>;\n\n const unit =\n intervals.find((intervalUnit) => {\n return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);\n }) ?? 'seconds';\n\n const value = interval[unit] ?? 0;\n const relativeTime = isPast(timestamp) ? -value : value;\n\n // Display custom text if interval is less than the threshold\n const customInterval = customIntervals.find(\n (custom) => interval[custom.unit] < custom.threshold\n );\n\n const displayText = customInterval\n ? customInterval.text\n : formatRelativeTime(relativeTime, unit, { numeric: 'auto' });\n\n return (\n <time\n ref={forwardedRef}\n dateTime={timestamp.toISOString()}\n role=\"time\"\n title={`${formatDate(timestamp)} ${formatTime(timestamp)}`}\n {...restProps}\n >\n {displayText}\n </time>\n );\n }\n);\n\nexport { RelativeTime };\nexport type { CustomInterval, RelativeTimeProps };\n"],"names":["intervals","RelativeTime","React","forwardRef","timestamp","customIntervals","restProps","forwardedRef","formatRelativeTime","formatDate","formatTime","useIntl","isValid","_jsx","time","ref","role","interval","intervalToDuration","start","end","Date","now","unit","find","intervalUnit","Object","keys","includes","value","relativeTime","isPast","customInterval","custom","threshold","displayText","text","numeric","dateTime","toISOString","title"],"mappings":";;;;;AAKA,MAAMA,SAAAA,GAAmC;AAAC,IAAA,OAAA;AAAS,IAAA,QAAA;AAAU,IAAA,MAAA;AAAQ,IAAA,OAAA;AAAS,IAAA,SAAA;AAAW,IAAA;AAAU,CAAA;AAanG;;;;;;;;;;;;;AAaC,IACD,MAAMC,YAAAA,iBAAeC,KAAAA,CAAMC,UAAU,CACnC,CAAC,EAAEC,SAAS,EAAEC,eAAAA,GAAkB,EAAE,EAAE,GAAGC,WAAW,EAAEC,YAAAA,GAAAA;AAClD,IAAA,MAAM,EAAEC,kBAAkB,EAAEC,UAAU,EAAEC,UAAU,EAAE,GAAGC,OAAAA,EAAAA;;IAGvD,IAAI,CAACC,QAAQR,SAAAA,CAAAA,EAAY;AACvB,QAAA,qBACES,GAAA,CAACC,MAAAA,EAAAA;YAAKC,GAAAA,EAAKR,YAAAA;YAAcS,IAAAA,EAAK,MAAA;AAAQ,YAAA,GAAGV,SAAS;AAAE,YAAA,QAAA,EAAA;;AAIxD,IAAA;AAEA;;QAGA,MAAMW,WAAWC,kBAAAA,CAAmB;QAClCC,KAAAA,EAAOf,SAAAA;AACPgB,QAAAA,GAAAA,EAAKC,KAAKC,GAAG;AAEf,KAAA,CAAA;AAEA,IAAA,MAAMC,IAAAA,GACJvB,SAAAA,CAAUwB,IAAI,CAAC,CAACC,YAAAA,GAAAA;QACd,OAAOR,QAAQ,CAACQ,YAAAA,CAAa,GAAG,CAAA,IAAKC,OAAOC,IAAI,CAACV,QAAAA,CAAAA,CAAUW,QAAQ,CAACH,YAAAA,CAAAA;IACtE,CAAA,CAAA,IAAM,SAAA;AAER,IAAA,MAAMI,KAAAA,GAAQZ,QAAQ,CAACM,IAAAA,CAAK,IAAI,CAAA;AAChC,IAAA,MAAMO,YAAAA,GAAeC,MAAAA,CAAO3B,SAAAA,CAAAA,GAAa,CAACyB,KAAAA,GAAQA,KAAAA;;AAGlD,IAAA,MAAMG,cAAAA,GAAiB3B,eAAAA,CAAgBmB,IAAI,CACzC,CAACS,MAAAA,GAAWhB,QAAQ,CAACgB,MAAAA,CAAOV,IAAI,CAAC,GAAGU,OAAOC,SAAS,CAAA;AAGtD,IAAA,MAAMC,cAAcH,cAAAA,GAChBA,cAAAA,CAAeI,IAAI,GACnB5B,kBAAAA,CAAmBsB,cAAcP,IAAAA,EAAM;QAAEc,OAAAA,EAAS;AAAO,KAAA,CAAA;AAE7D,IAAA,qBACExB,GAAA,CAACC,MAAAA,EAAAA;QACCC,GAAAA,EAAKR,YAAAA;AACL+B,QAAAA,QAAAA,EAAUlC,UAAUmC,WAAW,EAAA;QAC/BvB,IAAAA,EAAK,MAAA;AACLwB,QAAAA,KAAAA,EAAO,GAAG/B,UAAAA,CAAWL,SAAAA,CAAAA,CAAW,CAAC,EAAEM,WAAWN,SAAAA,CAAAA,CAAAA,CAAY;AACzD,QAAA,GAAGE,SAAS;AAEZ6B,QAAAA,QAAAA,EAAAA;;AAGP,CAAA;;;;"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var reactRouterDom = require('react-router-dom');
|
|
6
|
+
var MediaLibraryBanner = require('./MediaLibraryBanner.js');
|
|
7
|
+
var UpsellBanner = require('./UpsellBanner.js');
|
|
8
|
+
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @description Renders the admin's top banners, ensuring only one shows at a time instead of
|
|
31
|
+
* stacking: the Media Library banner takes priority over the upsell one. Kept as its own
|
|
32
|
+
* component (rather than inline in `AuthenticatedLayout`) so this wiring can be unit tested
|
|
33
|
+
* without the rest of the layout's unrelated dependencies (menu, tracking, app info, etc.).
|
|
34
|
+
*/ const TopBanners = ()=>{
|
|
35
|
+
// Seeded from the current route so `UpsellBanner` (and its trial-license query) doesn't
|
|
36
|
+
// mount-then-immediately-unmount on first render when landing directly on the Media Library.
|
|
37
|
+
// `MediaLibraryBanner`'s own `onVisibilityChange` corrects this afterwards if it turns out
|
|
38
|
+
// dismissed, same as it does for any other visibility change.
|
|
39
|
+
const isOnMediaLibraryRoute = reactRouterDom.useMatch('/plugins/upload/*') !== null;
|
|
40
|
+
const [isMediaLibraryBannerVisible, setIsMediaLibraryBannerVisible] = React__namespace.useState(isOnMediaLibraryRoute);
|
|
41
|
+
return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
42
|
+
children: [
|
|
43
|
+
!isMediaLibraryBannerVisible && /*#__PURE__*/ jsxRuntime.jsx(UpsellBanner.UpsellBanner, {}),
|
|
44
|
+
/*#__PURE__*/ jsxRuntime.jsx(MediaLibraryBanner.MediaLibraryBanner, {
|
|
45
|
+
onVisibilityChange: setIsMediaLibraryBannerVisible
|
|
46
|
+
})
|
|
47
|
+
]
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
exports.TopBanners = TopBanners;
|
|
52
|
+
//# sourceMappingURL=TopBanners.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TopBanners.js","sources":["../../../../../admin/src/components/TopBanners.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useMatch } from 'react-router-dom';\n\nimport { MediaLibraryBanner } from './MediaLibraryBanner';\nimport { UpsellBanner } from './UpsellBanner';\n\n/**\n * @description Renders the admin's top banners, ensuring only one shows at a time instead of\n * stacking: the Media Library banner takes priority over the upsell one. Kept as its own\n * component (rather than inline in `AuthenticatedLayout`) so this wiring can be unit tested\n * without the rest of the layout's unrelated dependencies (menu, tracking, app info, etc.).\n */\nconst TopBanners = () => {\n // Seeded from the current route so `UpsellBanner` (and its trial-license query) doesn't\n // mount-then-immediately-unmount on first render when landing directly on the Media Library.\n // `MediaLibraryBanner`'s own `onVisibilityChange` corrects this afterwards if it turns out\n // dismissed, same as it does for any other visibility change.\n const isOnMediaLibraryRoute = useMatch('/plugins/upload/*') !== null;\n const [isMediaLibraryBannerVisible, setIsMediaLibraryBannerVisible] =\n React.useState(isOnMediaLibraryRoute);\n\n return (\n <>\n {!isMediaLibraryBannerVisible && <UpsellBanner />}\n <MediaLibraryBanner onVisibilityChange={setIsMediaLibraryBannerVisible} />\n </>\n );\n};\n\nexport { TopBanners };\n"],"names":["TopBanners","isOnMediaLibraryRoute","useMatch","isMediaLibraryBannerVisible","setIsMediaLibraryBannerVisible","React","useState","_jsxs","_Fragment","_jsx","UpsellBanner","MediaLibraryBanner","onVisibilityChange"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA;;;;;AAKC,UACKA,UAAAA,GAAa,IAAA;;;;;IAKjB,MAAMC,qBAAAA,GAAwBC,wBAAS,mBAAA,CAAA,KAAyB,IAAA;AAChE,IAAA,MAAM,CAACC,2BAAAA,EAA6BC,8BAAAA,CAA+B,GACjEC,gBAAAA,CAAMC,QAAQ,CAACL,qBAAAA,CAAAA;IAEjB,qBACEM,eAAA,CAAAC,mBAAA,EAAA;;AACG,YAAA,CAACL,6CAA+BM,cAAA,CAACC,yBAAAA,EAAAA,EAAAA,CAAAA;0BAClCD,cAAA,CAACE,qCAAAA,EAAAA;gBAAmBC,kBAAAA,EAAoBR;;;;AAG9C;;;;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useMatch } from 'react-router-dom';
|
|
4
|
+
import { MediaLibraryBanner } from './MediaLibraryBanner.mjs';
|
|
5
|
+
import { UpsellBanner } from './UpsellBanner.mjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @description Renders the admin's top banners, ensuring only one shows at a time instead of
|
|
9
|
+
* stacking: the Media Library banner takes priority over the upsell one. Kept as its own
|
|
10
|
+
* component (rather than inline in `AuthenticatedLayout`) so this wiring can be unit tested
|
|
11
|
+
* without the rest of the layout's unrelated dependencies (menu, tracking, app info, etc.).
|
|
12
|
+
*/ const TopBanners = ()=>{
|
|
13
|
+
// Seeded from the current route so `UpsellBanner` (and its trial-license query) doesn't
|
|
14
|
+
// mount-then-immediately-unmount on first render when landing directly on the Media Library.
|
|
15
|
+
// `MediaLibraryBanner`'s own `onVisibilityChange` corrects this afterwards if it turns out
|
|
16
|
+
// dismissed, same as it does for any other visibility change.
|
|
17
|
+
const isOnMediaLibraryRoute = useMatch('/plugins/upload/*') !== null;
|
|
18
|
+
const [isMediaLibraryBannerVisible, setIsMediaLibraryBannerVisible] = React.useState(isOnMediaLibraryRoute);
|
|
19
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
20
|
+
children: [
|
|
21
|
+
!isMediaLibraryBannerVisible && /*#__PURE__*/ jsx(UpsellBanner, {}),
|
|
22
|
+
/*#__PURE__*/ jsx(MediaLibraryBanner, {
|
|
23
|
+
onVisibilityChange: setIsMediaLibraryBannerVisible
|
|
24
|
+
})
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { TopBanners };
|
|
30
|
+
//# sourceMappingURL=TopBanners.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TopBanners.mjs","sources":["../../../../../admin/src/components/TopBanners.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useMatch } from 'react-router-dom';\n\nimport { MediaLibraryBanner } from './MediaLibraryBanner';\nimport { UpsellBanner } from './UpsellBanner';\n\n/**\n * @description Renders the admin's top banners, ensuring only one shows at a time instead of\n * stacking: the Media Library banner takes priority over the upsell one. Kept as its own\n * component (rather than inline in `AuthenticatedLayout`) so this wiring can be unit tested\n * without the rest of the layout's unrelated dependencies (menu, tracking, app info, etc.).\n */\nconst TopBanners = () => {\n // Seeded from the current route so `UpsellBanner` (and its trial-license query) doesn't\n // mount-then-immediately-unmount on first render when landing directly on the Media Library.\n // `MediaLibraryBanner`'s own `onVisibilityChange` corrects this afterwards if it turns out\n // dismissed, same as it does for any other visibility change.\n const isOnMediaLibraryRoute = useMatch('/plugins/upload/*') !== null;\n const [isMediaLibraryBannerVisible, setIsMediaLibraryBannerVisible] =\n React.useState(isOnMediaLibraryRoute);\n\n return (\n <>\n {!isMediaLibraryBannerVisible && <UpsellBanner />}\n <MediaLibraryBanner onVisibilityChange={setIsMediaLibraryBannerVisible} />\n </>\n );\n};\n\nexport { TopBanners };\n"],"names":["TopBanners","isOnMediaLibraryRoute","useMatch","isMediaLibraryBannerVisible","setIsMediaLibraryBannerVisible","React","useState","_jsxs","_Fragment","_jsx","UpsellBanner","MediaLibraryBanner","onVisibilityChange"],"mappings":";;;;;;AAOA;;;;;AAKC,UACKA,UAAAA,GAAa,IAAA;;;;;IAKjB,MAAMC,qBAAAA,GAAwBC,SAAS,mBAAA,CAAA,KAAyB,IAAA;AAChE,IAAA,MAAM,CAACC,2BAAAA,EAA6BC,8BAAAA,CAA+B,GACjEC,KAAAA,CAAMC,QAAQ,CAACL,qBAAAA,CAAAA;IAEjB,qBACEM,IAAA,CAAAC,QAAA,EAAA;;AACG,YAAA,CAACL,6CAA+BM,GAAA,CAACC,YAAAA,EAAAA,EAAAA,CAAAA;0BAClCD,GAAA,CAACE,kBAAAA,EAAAA;gBAAmBC,kBAAAA,EAAoBR;;;;AAG9C;;;;"}
|
|
@@ -35,7 +35,8 @@ var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
|
35
35
|
/* -------------------------------------------------------------------------------------------------
|
|
36
36
|
* Context
|
|
37
37
|
* -----------------------------------------------------------------------------------------------*/ const TrackingContext = /*#__PURE__*/ React__namespace.createContext({
|
|
38
|
-
uuid: false
|
|
38
|
+
uuid: false,
|
|
39
|
+
isStrapiVersionReady: false
|
|
39
40
|
});
|
|
40
41
|
const TrackingProvider = ({ children })=>{
|
|
41
42
|
const token = Auth.useAuth('App', (state)=>state.token);
|
|
@@ -45,8 +46,14 @@ const TrackingProvider = ({ children })=>{
|
|
|
45
46
|
const { data } = admin.useTelemetryPropertiesQuery(undefined, {
|
|
46
47
|
skip: !initData?.uuid || !token
|
|
47
48
|
});
|
|
49
|
+
const versionQueryEnabled = Boolean(initData?.uuid && token);
|
|
50
|
+
const { data: appInfo, isLoading: isLoadingAppInfo, isError: isInformationError } = admin.useInformationQuery(undefined, {
|
|
51
|
+
skip: !versionQueryEnabled
|
|
52
|
+
});
|
|
53
|
+
const strapiVersion = appInfo?.strapiVersion;
|
|
54
|
+
const isStrapiVersionReady = Boolean(strapiVersion) || versionQueryEnabled && isInformationError;
|
|
48
55
|
React__namespace.useEffect(()=>{
|
|
49
|
-
if (uuid && data) {
|
|
56
|
+
if (uuid && data && !isLoadingAppInfo) {
|
|
50
57
|
const event = 'didInitializeAdministration';
|
|
51
58
|
try {
|
|
52
59
|
fetch(`${process.env.STRAPI_ANALYTICS_URL || 'https://analytics.strapi.io'}/api/v2/track`, {
|
|
@@ -59,7 +66,8 @@ const TrackingProvider = ({ children })=>{
|
|
|
59
66
|
groupProperties: {
|
|
60
67
|
...data,
|
|
61
68
|
projectId: uuid,
|
|
62
|
-
registeredWidgets: getAllWidgets().map((widget)=>widget.uid)
|
|
69
|
+
registeredWidgets: getAllWidgets().map((widget)=>widget.uid),
|
|
70
|
+
version: strapiVersion
|
|
63
71
|
}
|
|
64
72
|
}),
|
|
65
73
|
headers: {
|
|
@@ -74,14 +82,20 @@ const TrackingProvider = ({ children })=>{
|
|
|
74
82
|
}, [
|
|
75
83
|
data,
|
|
76
84
|
uuid,
|
|
77
|
-
getAllWidgets
|
|
85
|
+
getAllWidgets,
|
|
86
|
+
isLoadingAppInfo,
|
|
87
|
+
strapiVersion
|
|
78
88
|
]);
|
|
79
89
|
const value = React__namespace.useMemo(()=>({
|
|
80
90
|
uuid,
|
|
81
|
-
telemetryProperties: data
|
|
91
|
+
telemetryProperties: data,
|
|
92
|
+
strapiVersion,
|
|
93
|
+
isStrapiVersionReady
|
|
82
94
|
}), [
|
|
83
95
|
uuid,
|
|
84
|
-
data
|
|
96
|
+
data,
|
|
97
|
+
strapiVersion,
|
|
98
|
+
isStrapiVersionReady
|
|
85
99
|
]);
|
|
86
100
|
return /*#__PURE__*/ jsxRuntime.jsx(TrackingContext.Provider, {
|
|
87
101
|
value: value,
|
|
@@ -109,7 +123,7 @@ const TrackingProvider = ({ children })=>{
|
|
|
109
123
|
const deviceType = useDeviceType.useDeviceType();
|
|
110
124
|
const deviceTypeRef = React__namespace.useRef(deviceType);
|
|
111
125
|
deviceTypeRef.current = deviceType;
|
|
112
|
-
const { uuid, telemetryProperties } = React__namespace.useContext(TrackingContext);
|
|
126
|
+
const { uuid, telemetryProperties, strapiVersion } = React__namespace.useContext(TrackingContext);
|
|
113
127
|
const userId = AppInfo.useAppInfo('useTracking', (state)=>state.userId);
|
|
114
128
|
const trackUsage = React__namespace.useCallback(async (event, properties)=>{
|
|
115
129
|
try {
|
|
@@ -126,7 +140,8 @@ const TrackingProvider = ({ children })=>{
|
|
|
126
140
|
groupProperties: {
|
|
127
141
|
...telemetryProperties,
|
|
128
142
|
projectId: uuid,
|
|
129
|
-
projectType: window.strapi.projectType
|
|
143
|
+
projectType: window.strapi.projectType,
|
|
144
|
+
version: strapiVersion
|
|
130
145
|
}
|
|
131
146
|
}, {
|
|
132
147
|
headers: {
|
|
@@ -141,6 +156,7 @@ const TrackingProvider = ({ children })=>{
|
|
|
141
156
|
}
|
|
142
157
|
return null;
|
|
143
158
|
}, [
|
|
159
|
+
strapiVersion,
|
|
144
160
|
telemetryProperties,
|
|
145
161
|
userId,
|
|
146
162
|
uuid
|
|
@@ -149,7 +165,11 @@ const TrackingProvider = ({ children })=>{
|
|
|
149
165
|
trackUsage
|
|
150
166
|
};
|
|
151
167
|
};
|
|
168
|
+
/**
|
|
169
|
+
* Internal readiness signal for events that must wait for the provider's version.
|
|
170
|
+
*/ const useStrapiVersionReady = ()=>React__namespace.useContext(TrackingContext).isStrapiVersionReady;
|
|
152
171
|
|
|
153
172
|
exports.TrackingProvider = TrackingProvider;
|
|
173
|
+
exports.useStrapiVersionReady = useStrapiVersionReady;
|
|
154
174
|
exports.useTracking = useTracking;
|
|
155
175
|
//# sourceMappingURL=Tracking.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tracking.js","sources":["../../../../../admin/src/features/Tracking.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport axios, { AxiosResponse } from 'axios';\n\nimport { Tours } from '../components/GuidedTour/Tours';\nimport { useDeviceType } from '../hooks/useDeviceType';\nimport { useInitQuery, useTelemetryPropertiesQuery } from '../services/admin';\n\nimport { useAppInfo } from './AppInfo';\nimport { useAuth } from './Auth';\nimport { useStrapiApp } from './StrapiApp';\n\nexport interface TelemetryProperties {\n useTypescriptOnServer?: boolean;\n useTypescriptOnAdmin?: boolean;\n isHostedOnStrapiCloud?: boolean;\n numberOfAllContentTypes?: number;\n numberOfComponents?: number;\n numberOfDynamicZones?: number;\n numberOfContentTypeFolders?: number;\n}\n\nexport interface TrackingContextValue {\n uuid?: string | boolean;\n telemetryProperties?: TelemetryProperties;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\nconst TrackingContext = React.createContext<TrackingContextValue>({\n uuid: false,\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface TrackingProviderProps {\n children: React.ReactNode;\n}\n\nconst TrackingProvider = ({ children }: TrackingProviderProps) => {\n const token = useAuth('App', (state) => state.token);\n const { data: initData } = useInitQuery();\n const { uuid } = initData ?? {};\n const getAllWidgets = useStrapiApp('TrackingProvider', (state) => state.widgets.getAll);\n\n const { data } = useTelemetryPropertiesQuery(undefined, {\n skip: !initData?.uuid || !token,\n });\n React.useEffect(() => {\n if (uuid && data) {\n const event = 'didInitializeAdministration';\n try {\n fetch(`${process.env.STRAPI_ANALYTICS_URL || 'https://analytics.strapi.io'}/api/v2/track`, {\n method: 'POST',\n body: JSON.stringify({\n // This event is anonymous\n event,\n userId: '',\n eventPropeties: {},\n groupProperties: {\n ...data,\n projectId: uuid,\n registeredWidgets: getAllWidgets().map((widget) => widget.uid),\n },\n }),\n headers: {\n 'Content-Type': 'application/json',\n 'X-Strapi-Event': event,\n },\n });\n } catch {\n // silence is golden\n }\n }\n }, [data, uuid, getAllWidgets]);\n const value = React.useMemo(\n () => ({\n uuid,\n telemetryProperties: data,\n }),\n [uuid, data]\n );\n\n return <TrackingContext.Provider value={value}>{children}</TrackingContext.Provider>;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Hook\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * We can group these events together because none have properties so there's no benefit\n * to having them as separate types.\n *\n * Meanwhile those with properties have different property shapes corresponding to the specific\n * event so understanding which properties go with which event is very helpful.\n */\nexport interface EventWithoutProperties {\n name:\n | 'changeComponentsOrder'\n | 'didAddComponentToDynamicZone'\n | 'didBulkDeleteEntries'\n | 'didNotBulkDeleteEntries'\n | 'didChangeDisplayedFields'\n | 'didCheckDraftRelations'\n | 'didClickGuidedTourHomepageApiTokens'\n | 'didClickGuidedTourHomepageContentManager'\n | 'didClickGuidedTourHomepageContentTypeBuilder'\n | 'didClickGuidedTourStep1CollectionType'\n | 'didClickGuidedTourStep2ContentManager'\n | 'didClickGuidedTourStep3ApiTokens'\n | 'didClickonBlogSection'\n | 'didClickonCodeExampleSection'\n | 'didClickonReadTheDocumentationSection'\n | 'didClickOnTryStrapiCloudSection'\n | 'didClickonTutorialSection'\n | 'didCreateGuidedTourCollectionType'\n | 'didCreateGuidedTourEntry'\n | 'didCreateNewRole'\n | 'didCreateRole'\n | 'didDeleteToken'\n | 'didDuplicateRole'\n | 'didEditEditSettings'\n | 'didEditEmailTemplates'\n | 'didEditFieldNameOnContentType'\n | 'didEditListSettings'\n | 'didEditMediaLibraryConfig'\n | 'didEditNameOfContentType'\n | 'didGenerateGuidedTourApiTokens'\n | 'didLaunchGuidedtour'\n | 'didNotCreateFirstAdmin'\n | 'didNotSaveComponent'\n | 'didPluginLearnMore'\n | 'didBulkPublishEntries'\n | 'didNotBulkPublishEntries'\n | 'didUnpublishEntry'\n | 'didBulkUnpublishEntries'\n | 'didNotBulkUnpublishEntries'\n | 'didSaveComponent'\n | 'didSaveContentType'\n | 'didSearch'\n | 'didSkipGuidedtour'\n | 'didSubmitPlugin'\n | 'didSubmitProvider'\n | 'didUpdateConditions'\n | 'didSelectAllMediaLibraryElements'\n | 'didSelectContentTypeFieldSettings'\n | 'didSelectContentTypeSettings'\n | 'didEditAuthenticationProvider'\n | 'didRestoreHistoryVersion'\n | 'hasClickedCTBAddFieldBanner'\n | 'removeComponentFromDynamicZone'\n | 'willAddMoreFieldToContentType'\n | 'willBulkDeleteEntries'\n | 'willBulkPublishEntries'\n | 'willBulkUnpublishEntries'\n | 'willChangeNumberOfEntriesPerPage'\n | 'willCheckDraftRelations'\n | 'willCreateComponent'\n | 'willCreateComponentFromAttributesModal'\n | 'willCreateContentType'\n | 'willCreateFirstAdmin'\n | 'willCreateNewRole'\n | 'willCreateRole'\n | 'willCreateSingleType'\n | 'willCreateStage'\n | 'willCreateWorkflow'\n | 'willDeleteEntryFromList'\n | 'willDeleteFieldOfContentType'\n | 'willDuplicateRole'\n | 'willEditEditLayout'\n | 'willEditEmailTemplates'\n | 'willEditEntryFromButton'\n | 'willEditEntryFromList'\n | 'willEditReleaseFromHome'\n | 'willEditFieldOfContentType'\n | 'willEditMediaLibraryConfig'\n | 'willEditNameOfContentType'\n | 'willEditNameOfSingleType'\n | 'willEditAuthenticationProvider'\n | 'willEditFieldNameOnContentType'\n | 'willEditStage'\n | 'willFilterEntries'\n | 'willInstallPlugin'\n | 'willOpenAuditLogDetailsFromHome'\n | 'willUnpublishEntry'\n | 'willSaveComponent'\n | 'willSaveContentType'\n | 'willSaveContentTypeLayout'\n | 'didEditFieldNameOnContentType'\n | 'didCreateRelease'\n | 'didStartNewChat'\n | 'didLaunchGuidedtour'\n | 'didEditAICaption'\n | 'didEditAIAlternativeText'\n | 'didGenerateMetadataRetroactively'\n | 'didActOnFolders';\n\n properties?: never;\n}\n\ninterface DidAccessAuthenticatedAdministrationEvent {\n name: 'didAccessAuthenticatedAdministration';\n properties: {\n registeredWidgets: string[];\n projectId: string;\n };\n}\n\ninterface DidFilterMediaLibraryElementsEvent {\n name: 'didFilterMediaLibraryElements';\n properties: MediaEvents['properties'] & {\n filter: string;\n };\n}\n\ninterface DidSortMediaLibraryElementsEvent {\n name: 'didSortMediaLibraryElements';\n properties: MediaEvents['properties'] & {\n sort: string;\n };\n}\n\ninterface DidCropFileEvent {\n name: 'didCropFile';\n properties: MediaEvents['properties'] & {\n duplicatedFile: null | boolean;\n };\n}\n\ninterface DidSelectFile {\n name: 'didSelectFile';\n properties: MediaEvents['properties'] & {\n source: 'url' | 'computer';\n };\n}\n\ninterface DidEditMediaLibraryElementsEvent {\n name: 'didEditMediaLibraryElements';\n properties: MediaEvents['properties'] & {\n type: string;\n changeLocation: string | boolean;\n };\n}\n\ninterface MediaEvents {\n name:\n | 'didSearchMediaLibraryElements'\n | 'didReplaceMedia'\n | 'didAddMediaLibraryFolders'\n | 'willAddMediaLibraryAssets';\n properties: {\n location: string;\n };\n}\n\ninterface DidSelectContentTypeFieldTypeEvent {\n name: 'didSelectContentTypeFieldType';\n properties: {\n type?: string;\n };\n}\n\ninterface DidChangeModeEvent {\n name: 'didChangeMode';\n properties: {\n newMode: string;\n };\n}\ninterface DidSubmitWithErrorsFirstAdminEvent {\n name: 'didSubmitWithErrorsFirstAdmin';\n properties: {\n count: string;\n };\n}\n\ninterface WillNavigateEvent {\n name: 'willNavigate';\n properties: {\n from: string;\n to: string;\n };\n}\n\ninterface DidClickOnDocLink {\n name: 'didClickOnDocLink';\n properties: {\n from: string;\n to: string;\n };\n}\n\ninterface DidAccessTokenListEvent {\n name: 'didAccessTokenList';\n properties: {\n tokenType: TokenEvents['properties']['tokenType'];\n number: number;\n };\n}\ninterface LogoEvent {\n name: 'didChangeLogo' | 'didClickResetLogo';\n properties: {\n logo: 'menu' | 'auth';\n };\n}\n\ninterface TokenEvents {\n name:\n | 'didCopyTokenKey'\n | 'didAddTokenFromList'\n | 'didEditTokenFromList'\n | 'willAccessTokenList'\n | 'willAddTokenFromList'\n | 'willCreateToken'\n | 'willDeleteToken'\n | 'willEditToken'\n | 'willEditTokenFromList';\n properties: {\n tokenType: 'api-token' | 'transfer-token';\n };\n}\n\ninterface WillModifyTokenEvent {\n name: 'didCreateToken' | 'didEditToken';\n properties: {\n tokenType: TokenEvents['properties']['tokenType'];\n kind?: 'admin' | 'content-api';\n type?: 'custom' | 'full-access' | 'read-only' | Array<'push' | 'pull' | 'push-pull'>;\n };\n}\n\ninterface DeleteEntryEvents {\n name: 'willDeleteEntry' | 'didDeleteEntry' | 'didNotDeleteEntry';\n properties: {\n status?: string;\n error?: unknown;\n };\n}\n\ninterface CreateEntryEvents {\n name: 'willCreateEntry' | 'didCreateEntry' | 'didNotCreateEntry';\n properties: {\n documentId?: string;\n status?: string;\n error?: unknown;\n fromPreview?: boolean;\n fromRelationModal?: boolean;\n };\n}\n\ninterface PublishEntryEvents {\n name: 'willPublishEntry' | 'didPublishEntry';\n properties: {\n documentId?: string;\n fromPreview?: boolean;\n fromRelationModal?: boolean;\n };\n}\n\ninterface UpdateEntryEvents {\n name: 'willEditEntry' | 'didEditEntry' | 'didNotEditEntry';\n properties: {\n documentId?: string;\n status?: string;\n error?: unknown;\n fromPreview?: boolean;\n fromRelationModal?: boolean;\n };\n}\n\ninterface DidFilterEntriesEvent {\n name: 'didFilterEntries';\n properties: {\n useRelation: boolean;\n };\n}\n\ninterface DidPublishRelease {\n name: 'didPublishRelease';\n properties: {\n totalEntries: number;\n totalPublishedEntries: number;\n totalUnpublishedEntries: number;\n };\n}\n\ninterface DidUsePresetPromptEvent {\n name: 'didUsePresetPrompt';\n properties: {\n promptType:\n | 'generate-product-schema'\n | 'tell-me-about-the-content-type-builder'\n | 'tell-me-about-strapi';\n };\n}\n\ninterface DidAnswerMessageEvent {\n name: 'didAnswerMessage';\n properties: {\n successful: boolean;\n };\n}\n\ninterface DidVoteAnswerEvent {\n name: 'didVoteAnswer';\n properties: {\n value: 'positive' | 'negative';\n };\n}\n\ninterface DidUpdateCTBSchema {\n name: 'didUpdateCTBSchema';\n properties: {\n success: boolean;\n newContentTypes: number;\n editedContentTypes: number;\n deletedContentTypes: number;\n newComponents: number;\n editedComponents: number;\n deletedComponents: number;\n newFields: number;\n editedFields: number;\n deletedFields: number;\n };\n}\n\ninterface DidSkipGuidedTour {\n name: 'didSkipGuidedTour';\n properties: {\n name: keyof Tours | 'all';\n };\n}\n\ninterface DidCompleteGuidedTour {\n name: 'didCompleteGuidedTour';\n properties: {\n name: keyof Tours | 'all';\n };\n}\n\ninterface DidStartGuidedTour {\n name: 'didStartGuidedTour';\n properties: {\n name: keyof Tours;\n fromHomepage?: boolean;\n };\n}\n\ninterface WillEditEntryFromHome {\n name: 'willEditEntryFromHome';\n properties: {\n entryType: 'edited' | 'published' | 'assigned';\n };\n}\n\ninterface DidOpenHomeWidgetLink {\n name: 'didOpenHomeWidgetLink';\n properties: {\n widgetUID: string;\n };\n}\n\ninterface DidOpenKeyStatisticsWidgetLink {\n name: 'didOpenKeyStatisticsWidgetLink';\n properties: {\n itemKey: string;\n };\n}\n\ntype EventsWithProperties =\n | CreateEntryEvents\n | PublishEntryEvents\n | DidAccessAuthenticatedAdministrationEvent\n | DidAccessTokenListEvent\n | DidChangeModeEvent\n | DidCropFileEvent\n | DeleteEntryEvents\n | DidEditMediaLibraryElementsEvent\n | DidFilterMediaLibraryElementsEvent\n | DidFilterEntriesEvent\n | DidSelectContentTypeFieldTypeEvent\n | DidSelectFile\n | DidSortMediaLibraryElementsEvent\n | DidSubmitWithErrorsFirstAdminEvent\n | DidUsePresetPromptEvent\n | DidAnswerMessageEvent\n | DidVoteAnswerEvent\n | LogoEvent\n | TokenEvents\n | UpdateEntryEvents\n | WillModifyTokenEvent\n | WillNavigateEvent\n | DidClickOnDocLink\n | DidPublishRelease\n | MediaEvents\n | DidUpdateCTBSchema\n | DidSkipGuidedTour\n | DidCompleteGuidedTour\n | DidStartGuidedTour\n | DidOpenHomeWidgetLink\n | DidOpenKeyStatisticsWidgetLink\n | WillEditEntryFromHome;\n\nexport type TrackingEvent = EventWithoutProperties | EventsWithProperties;\nexport interface UseTrackingReturn {\n /**\n * This type helps show all the available event names before you start typing,\n * however autocomplete isn't great.\n */\n trackUsage<TEvent extends TrackingEvent>(\n event: TEvent['name'],\n properties: TEvent['properties']\n ): Promise<null | AxiosResponse<string>>;\n trackUsage<TEvent extends Extract<TrackingEvent, { properties?: never }>>(\n event: TEvent['name'],\n properties?: never\n ): Promise<null | AxiosResponse<string>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n trackUsage<TEvent extends Extract<TrackingEvent, { properties: object }>>(\n event: TEvent['name'],\n properties: TEvent['properties']\n ): Promise<null | AxiosResponse<string>>;\n}\n\n/**\n * @description Used to send amplitude events to the Strapi Tracking hub.\n *\n * @example\n * ```tsx\n * import { useTracking } from '@strapi/strapi/admin';\n *\n * const MyComponent = () => {\n * const { trackUsage } = useTracking();\n *\n * const handleClick = () => {\n * trackUsage('my-event', { myProperty: 'myValue' });\n * }\n *\n * return <button onClick={handleClick}>Send Event</button>\n * }\n * ```\n */\nconst useTracking = (): UseTrackingReturn => {\n const deviceType = useDeviceType();\n const deviceTypeRef = React.useRef(deviceType);\n deviceTypeRef.current = deviceType;\n const { uuid, telemetryProperties } = React.useContext(TrackingContext);\n const userId = useAppInfo('useTracking', (state) => state.userId);\n const trackUsage = React.useCallback(\n async <TEvent extends TrackingEvent>(\n event: TEvent['name'],\n properties?: TEvent['properties']\n ) => {\n try {\n if (uuid && !window.strapi.telemetryDisabled) {\n const res = await axios.post<string>(\n `${process.env.STRAPI_ANALYTICS_URL || 'https://analytics.strapi.io'}/api/v2/track`,\n {\n event,\n userId,\n eventProperties: { ...properties },\n userProperties: {\n deviceType: deviceTypeRef.current,\n },\n groupProperties: {\n ...telemetryProperties,\n projectId: uuid,\n projectType: window.strapi.projectType,\n },\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'X-Strapi-Event': event,\n },\n }\n );\n\n return res;\n }\n } catch {\n // Silence is golden\n }\n\n return null;\n },\n [telemetryProperties, userId, uuid]\n );\n\n return { trackUsage };\n};\n\nexport { TrackingProvider, useTracking };\n"],"names":["TrackingContext","React","createContext","uuid","TrackingProvider","children","token","useAuth","state","data","initData","useInitQuery","getAllWidgets","useStrapiApp","widgets","getAll","useTelemetryPropertiesQuery","undefined","skip","useEffect","event","fetch","process","env","STRAPI_ANALYTICS_URL","method","body","JSON","stringify","userId","eventPropeties","groupProperties","projectId","registeredWidgets","map","widget","uid","headers","value","useMemo","telemetryProperties","_jsx","Provider","useTracking","deviceType","useDeviceType","deviceTypeRef","useRef","current","useContext","useAppInfo","trackUsage","useCallback","properties","window","strapi","telemetryDisabled","res","axios","post","eventProperties","userProperties","projectType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Tracking.js","sources":["../../../../../admin/src/features/Tracking.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport axios, { AxiosResponse } from 'axios';\n\nimport { Tours } from '../components/GuidedTour/Tours';\nimport { useDeviceType } from '../hooks/useDeviceType';\nimport { useInformationQuery, useInitQuery, useTelemetryPropertiesQuery } from '../services/admin';\n\nimport { useAppInfo } from './AppInfo';\nimport { useAuth } from './Auth';\nimport { useStrapiApp } from './StrapiApp';\n\nexport interface TelemetryProperties {\n useTypescriptOnServer?: boolean;\n useTypescriptOnAdmin?: boolean;\n isHostedOnStrapiCloud?: boolean;\n numberOfAllContentTypes?: number;\n numberOfComponents?: number;\n numberOfDynamicZones?: number;\n numberOfContentTypeFolders?: number;\n}\n\nexport interface TrackingContextValue {\n uuid?: string | boolean;\n telemetryProperties?: TelemetryProperties;\n strapiVersion?: string | null;\n /**\n * True once the version that `trackUsage` will attach is known, or the\n * information request has failed. Callers that must send a single event\n * wait for this so a later version update does not send the event again.\n */\n isStrapiVersionReady: boolean;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Context\n * -----------------------------------------------------------------------------------------------*/\n\nconst TrackingContext = React.createContext<TrackingContextValue>({\n uuid: false,\n isStrapiVersionReady: false,\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Provider\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface TrackingProviderProps {\n children: React.ReactNode;\n}\n\nconst TrackingProvider = ({ children }: TrackingProviderProps) => {\n const token = useAuth('App', (state) => state.token);\n const { data: initData } = useInitQuery();\n const { uuid } = initData ?? {};\n const getAllWidgets = useStrapiApp('TrackingProvider', (state) => state.widgets.getAll);\n\n const { data } = useTelemetryPropertiesQuery(undefined, {\n skip: !initData?.uuid || !token,\n });\n const versionQueryEnabled = Boolean(initData?.uuid && token);\n const {\n data: appInfo,\n isLoading: isLoadingAppInfo,\n isError: isInformationError,\n } = useInformationQuery(undefined, {\n skip: !versionQueryEnabled,\n });\n const strapiVersion = appInfo?.strapiVersion;\n const isStrapiVersionReady =\n Boolean(strapiVersion) || (versionQueryEnabled && isInformationError);\n React.useEffect(() => {\n if (uuid && data && !isLoadingAppInfo) {\n const event = 'didInitializeAdministration';\n try {\n fetch(`${process.env.STRAPI_ANALYTICS_URL || 'https://analytics.strapi.io'}/api/v2/track`, {\n method: 'POST',\n body: JSON.stringify({\n // This event is anonymous\n event,\n userId: '',\n eventPropeties: {},\n groupProperties: {\n ...data,\n projectId: uuid,\n registeredWidgets: getAllWidgets().map((widget) => widget.uid),\n version: strapiVersion,\n },\n }),\n headers: {\n 'Content-Type': 'application/json',\n 'X-Strapi-Event': event,\n },\n });\n } catch {\n // silence is golden\n }\n }\n }, [data, uuid, getAllWidgets, isLoadingAppInfo, strapiVersion]);\n const value = React.useMemo(\n () => ({\n uuid,\n telemetryProperties: data,\n strapiVersion,\n isStrapiVersionReady,\n }),\n [uuid, data, strapiVersion, isStrapiVersionReady]\n );\n\n return <TrackingContext.Provider value={value}>{children}</TrackingContext.Provider>;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * Hook\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * We can group these events together because none have properties so there's no benefit\n * to having them as separate types.\n *\n * Meanwhile those with properties have different property shapes corresponding to the specific\n * event so understanding which properties go with which event is very helpful.\n */\nexport interface EventWithoutProperties {\n name:\n | 'changeComponentsOrder'\n | 'didAddComponentToDynamicZone'\n | 'didBulkDeleteEntries'\n | 'didNotBulkDeleteEntries'\n | 'didChangeDisplayedFields'\n | 'didCheckDraftRelations'\n | 'didClickGuidedTourHomepageApiTokens'\n | 'didClickGuidedTourHomepageContentManager'\n | 'didClickGuidedTourHomepageContentTypeBuilder'\n | 'didClickGuidedTourStep1CollectionType'\n | 'didClickGuidedTourStep2ContentManager'\n | 'didClickGuidedTourStep3ApiTokens'\n | 'didClickonBlogSection'\n | 'didClickonCodeExampleSection'\n | 'didClickonReadTheDocumentationSection'\n | 'didClickOnTryStrapiCloudSection'\n | 'didClickonTutorialSection'\n | 'didCreateGuidedTourCollectionType'\n | 'didCreateGuidedTourEntry'\n | 'didCreateNewRole'\n | 'didCreateRole'\n | 'didDeleteToken'\n | 'didDuplicateRole'\n | 'didEditEditSettings'\n | 'didEditEmailTemplates'\n | 'didEditFieldNameOnContentType'\n | 'didEditListSettings'\n | 'didEditMediaLibraryConfig'\n | 'didEditNameOfContentType'\n | 'didGenerateGuidedTourApiTokens'\n | 'didLaunchGuidedtour'\n | 'didNotCreateFirstAdmin'\n | 'didNotSaveComponent'\n | 'didPluginLearnMore'\n | 'didBulkPublishEntries'\n | 'didNotBulkPublishEntries'\n | 'didUnpublishEntry'\n | 'didBulkUnpublishEntries'\n | 'didNotBulkUnpublishEntries'\n | 'didSaveComponent'\n | 'didSaveContentType'\n | 'didSearch'\n | 'didSkipGuidedtour'\n | 'didSubmitPlugin'\n | 'didSubmitProvider'\n | 'didUpdateConditions'\n | 'didSelectAllMediaLibraryElements'\n | 'didSelectContentTypeFieldSettings'\n | 'didSelectContentTypeSettings'\n | 'didEditAuthenticationProvider'\n | 'didRestoreHistoryVersion'\n | 'hasClickedCTBAddFieldBanner'\n | 'removeComponentFromDynamicZone'\n | 'willAddMoreFieldToContentType'\n | 'willBulkDeleteEntries'\n | 'willBulkPublishEntries'\n | 'willBulkUnpublishEntries'\n | 'willChangeNumberOfEntriesPerPage'\n | 'willCheckDraftRelations'\n | 'willCreateComponent'\n | 'willCreateComponentFromAttributesModal'\n | 'willCreateContentType'\n | 'willCreateFirstAdmin'\n | 'willCreateNewRole'\n | 'willCreateRole'\n | 'willCreateSingleType'\n | 'willCreateStage'\n | 'willCreateWorkflow'\n | 'willDeleteEntryFromList'\n | 'willDeleteFieldOfContentType'\n | 'willDuplicateRole'\n | 'willEditEditLayout'\n | 'willEditEmailTemplates'\n | 'willEditEntryFromButton'\n | 'willEditEntryFromList'\n | 'willEditReleaseFromHome'\n | 'willEditFieldOfContentType'\n | 'willEditMediaLibraryConfig'\n | 'willEditNameOfContentType'\n | 'willEditNameOfSingleType'\n | 'willEditAuthenticationProvider'\n | 'willEditFieldNameOnContentType'\n | 'willEditStage'\n | 'willFilterEntries'\n | 'willInstallPlugin'\n | 'willOpenAuditLogDetailsFromHome'\n | 'willUnpublishEntry'\n | 'willSaveComponent'\n | 'willSaveContentType'\n | 'willSaveContentTypeLayout'\n | 'didEditFieldNameOnContentType'\n | 'didCreateRelease'\n | 'didStartNewChat'\n | 'didLaunchGuidedtour'\n | 'didEditAICaption'\n | 'didEditAIAlternativeText'\n | 'didGenerateMetadataRetroactively'\n | 'didActOnFolders';\n\n properties?: never;\n}\n\ninterface DidAccessAuthenticatedAdministrationEvent {\n name: 'didAccessAuthenticatedAdministration';\n properties: {\n registeredWidgets: string[];\n projectId: string;\n };\n}\n\ninterface DidFilterMediaLibraryElementsEvent {\n name: 'didFilterMediaLibraryElements';\n properties: MediaEvents['properties'] & {\n filter: string;\n };\n}\n\ninterface DidSortMediaLibraryElementsEvent {\n name: 'didSortMediaLibraryElements';\n properties: MediaEvents['properties'] & {\n sort: string;\n };\n}\n\ninterface DidCropFileEvent {\n name: 'didCropFile';\n properties: MediaEvents['properties'] & {\n duplicatedFile: null | boolean;\n };\n}\n\ninterface DidSelectFile {\n name: 'didSelectFile';\n properties: MediaEvents['properties'] & {\n source: 'url' | 'computer';\n };\n}\n\ninterface DidEditMediaLibraryElementsEvent {\n name: 'didEditMediaLibraryElements';\n properties: MediaEvents['properties'] & {\n type: string;\n changeLocation: string | boolean;\n };\n}\n\ninterface MediaEvents {\n name:\n | 'didSearchMediaLibraryElements'\n | 'didReplaceMedia'\n | 'didAddMediaLibraryFolders'\n | 'willAddMediaLibraryAssets';\n properties: {\n location: string;\n };\n}\n\ninterface DidSelectContentTypeFieldTypeEvent {\n name: 'didSelectContentTypeFieldType';\n properties: {\n type?: string;\n };\n}\n\ninterface DidChangeModeEvent {\n name: 'didChangeMode';\n properties: {\n newMode: string;\n };\n}\ninterface DidSubmitWithErrorsFirstAdminEvent {\n name: 'didSubmitWithErrorsFirstAdmin';\n properties: {\n count: string;\n };\n}\n\ninterface WillNavigateEvent {\n name: 'willNavigate';\n properties: {\n from: string;\n to: string;\n };\n}\n\ninterface DidClickOnDocLink {\n name: 'didClickOnDocLink';\n properties: {\n from: string;\n to: string;\n };\n}\n\ninterface DidAccessTokenListEvent {\n name: 'didAccessTokenList';\n properties: {\n tokenType: TokenEvents['properties']['tokenType'];\n number: number;\n };\n}\ninterface LogoEvent {\n name: 'didChangeLogo' | 'didClickResetLogo';\n properties: {\n logo: 'menu' | 'auth';\n };\n}\n\ninterface TokenEvents {\n name:\n | 'didCopyTokenKey'\n | 'didAddTokenFromList'\n | 'didEditTokenFromList'\n | 'willAccessTokenList'\n | 'willAddTokenFromList'\n | 'willCreateToken'\n | 'willDeleteToken'\n | 'willEditToken'\n | 'willEditTokenFromList';\n properties: {\n tokenType: 'api-token' | 'transfer-token';\n };\n}\n\ninterface WillModifyTokenEvent {\n name: 'didCreateToken' | 'didEditToken';\n properties: {\n tokenType: TokenEvents['properties']['tokenType'];\n kind?: 'admin' | 'content-api';\n type?: 'custom' | 'full-access' | 'read-only' | Array<'push' | 'pull' | 'push-pull'>;\n };\n}\n\ninterface DeleteEntryEvents {\n name: 'willDeleteEntry' | 'didDeleteEntry' | 'didNotDeleteEntry';\n properties: {\n status?: string;\n error?: unknown;\n };\n}\n\ninterface CreateEntryEvents {\n name: 'willCreateEntry' | 'didCreateEntry' | 'didNotCreateEntry';\n properties: {\n documentId?: string;\n status?: string;\n error?: unknown;\n fromPreview?: boolean;\n fromRelationModal?: boolean;\n };\n}\n\ninterface PublishEntryEvents {\n name: 'willPublishEntry' | 'didPublishEntry';\n properties: {\n documentId?: string;\n fromPreview?: boolean;\n fromRelationModal?: boolean;\n };\n}\n\ninterface UpdateEntryEvents {\n name: 'willEditEntry' | 'didEditEntry' | 'didNotEditEntry';\n properties: {\n documentId?: string;\n status?: string;\n error?: unknown;\n fromPreview?: boolean;\n fromRelationModal?: boolean;\n };\n}\n\ninterface DidFilterEntriesEvent {\n name: 'didFilterEntries';\n properties: {\n useRelation: boolean;\n };\n}\n\ninterface DidPublishRelease {\n name: 'didPublishRelease';\n properties: {\n totalEntries: number;\n totalPublishedEntries: number;\n totalUnpublishedEntries: number;\n };\n}\n\ninterface DidUsePresetPromptEvent {\n name: 'didUsePresetPrompt';\n properties: {\n promptType:\n | 'generate-product-schema'\n | 'tell-me-about-the-content-type-builder'\n | 'tell-me-about-strapi';\n };\n}\n\ninterface DidAnswerMessageEvent {\n name: 'didAnswerMessage';\n properties: {\n successful: boolean;\n };\n}\n\ninterface DidVoteAnswerEvent {\n name: 'didVoteAnswer';\n properties: {\n value: 'positive' | 'negative';\n };\n}\n\ninterface DidUpdateCTBSchema {\n name: 'didUpdateCTBSchema';\n properties: {\n success: boolean;\n newContentTypes: number;\n editedContentTypes: number;\n deletedContentTypes: number;\n newComponents: number;\n editedComponents: number;\n deletedComponents: number;\n newFields: number;\n editedFields: number;\n deletedFields: number;\n };\n}\n\ninterface DidSkipGuidedTour {\n name: 'didSkipGuidedTour';\n properties: {\n name: keyof Tours | 'all';\n };\n}\n\ninterface DidCompleteGuidedTour {\n name: 'didCompleteGuidedTour';\n properties: {\n name: keyof Tours | 'all';\n };\n}\n\ninterface DidStartGuidedTour {\n name: 'didStartGuidedTour';\n properties: {\n name: keyof Tours;\n fromHomepage?: boolean;\n };\n}\n\ninterface WillEditEntryFromHome {\n name: 'willEditEntryFromHome';\n properties: {\n entryType: 'edited' | 'published' | 'assigned';\n };\n}\n\ninterface DidOpenHomeWidgetLink {\n name: 'didOpenHomeWidgetLink';\n properties: {\n widgetUID: string;\n };\n}\n\ninterface DidOpenKeyStatisticsWidgetLink {\n name: 'didOpenKeyStatisticsWidgetLink';\n properties: {\n itemKey: string;\n };\n}\n\ntype EventsWithProperties =\n | CreateEntryEvents\n | PublishEntryEvents\n | DidAccessAuthenticatedAdministrationEvent\n | DidAccessTokenListEvent\n | DidChangeModeEvent\n | DidCropFileEvent\n | DeleteEntryEvents\n | DidEditMediaLibraryElementsEvent\n | DidFilterMediaLibraryElementsEvent\n | DidFilterEntriesEvent\n | DidSelectContentTypeFieldTypeEvent\n | DidSelectFile\n | DidSortMediaLibraryElementsEvent\n | DidSubmitWithErrorsFirstAdminEvent\n | DidUsePresetPromptEvent\n | DidAnswerMessageEvent\n | DidVoteAnswerEvent\n | LogoEvent\n | TokenEvents\n | UpdateEntryEvents\n | WillModifyTokenEvent\n | WillNavigateEvent\n | DidClickOnDocLink\n | DidPublishRelease\n | MediaEvents\n | DidUpdateCTBSchema\n | DidSkipGuidedTour\n | DidCompleteGuidedTour\n | DidStartGuidedTour\n | DidOpenHomeWidgetLink\n | DidOpenKeyStatisticsWidgetLink\n | WillEditEntryFromHome;\n\nexport type TrackingEvent = EventWithoutProperties | EventsWithProperties;\nexport interface UseTrackingReturn {\n /**\n * This type helps show all the available event names before you start typing,\n * however autocomplete isn't great.\n */\n trackUsage<TEvent extends TrackingEvent>(\n event: TEvent['name'],\n properties: TEvent['properties']\n ): Promise<null | AxiosResponse<string>>;\n trackUsage<TEvent extends Extract<TrackingEvent, { properties?: never }>>(\n event: TEvent['name'],\n properties?: never\n ): Promise<null | AxiosResponse<string>>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n trackUsage<TEvent extends Extract<TrackingEvent, { properties: object }>>(\n event: TEvent['name'],\n properties: TEvent['properties']\n ): Promise<null | AxiosResponse<string>>;\n}\n\n/**\n * @description Used to send amplitude events to the Strapi Tracking hub.\n *\n * @example\n * ```tsx\n * import { useTracking } from '@strapi/strapi/admin';\n *\n * const MyComponent = () => {\n * const { trackUsage } = useTracking();\n *\n * const handleClick = () => {\n * trackUsage('my-event', { myProperty: 'myValue' });\n * }\n *\n * return <button onClick={handleClick}>Send Event</button>\n * }\n * ```\n */\nconst useTracking = (): UseTrackingReturn => {\n const deviceType = useDeviceType();\n const deviceTypeRef = React.useRef(deviceType);\n deviceTypeRef.current = deviceType;\n const { uuid, telemetryProperties, strapiVersion } = React.useContext(TrackingContext);\n const userId = useAppInfo('useTracking', (state) => state.userId);\n const trackUsage = React.useCallback(\n async <TEvent extends TrackingEvent>(\n event: TEvent['name'],\n properties?: TEvent['properties']\n ) => {\n try {\n if (uuid && !window.strapi.telemetryDisabled) {\n const res = await axios.post<string>(\n `${process.env.STRAPI_ANALYTICS_URL || 'https://analytics.strapi.io'}/api/v2/track`,\n {\n event,\n userId,\n eventProperties: { ...properties },\n userProperties: {\n deviceType: deviceTypeRef.current,\n },\n groupProperties: {\n ...telemetryProperties,\n projectId: uuid,\n projectType: window.strapi.projectType,\n version: strapiVersion,\n },\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'X-Strapi-Event': event,\n },\n }\n );\n\n return res;\n }\n } catch {\n // Silence is golden\n }\n\n return null;\n },\n [strapiVersion, telemetryProperties, userId, uuid]\n );\n\n return { trackUsage };\n};\n\n/**\n * Internal readiness signal for events that must wait for the provider's version.\n */\nconst useStrapiVersionReady = () => React.useContext(TrackingContext).isStrapiVersionReady;\n\nexport { TrackingProvider, useTracking, useStrapiVersionReady };\n"],"names":["TrackingContext","React","createContext","uuid","isStrapiVersionReady","TrackingProvider","children","token","useAuth","state","data","initData","useInitQuery","getAllWidgets","useStrapiApp","widgets","getAll","useTelemetryPropertiesQuery","undefined","skip","versionQueryEnabled","Boolean","appInfo","isLoading","isLoadingAppInfo","isError","isInformationError","useInformationQuery","strapiVersion","useEffect","event","fetch","process","env","STRAPI_ANALYTICS_URL","method","body","JSON","stringify","userId","eventPropeties","groupProperties","projectId","registeredWidgets","map","widget","uid","version","headers","value","useMemo","telemetryProperties","_jsx","Provider","useTracking","deviceType","useDeviceType","deviceTypeRef","useRef","current","useContext","useAppInfo","trackUsage","useCallback","properties","window","strapi","telemetryDisabled","res","axios","post","eventProperties","userProperties","projectType","useStrapiVersionReady"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import axios from 'axios';
|
|
4
4
|
import { useDeviceType } from '../hooks/useDeviceType.mjs';
|
|
5
|
-
import { useInitQuery, useTelemetryPropertiesQuery } from '../services/admin.mjs';
|
|
5
|
+
import { useInitQuery, useTelemetryPropertiesQuery, useInformationQuery } from '../services/admin.mjs';
|
|
6
6
|
import { useAppInfo } from './AppInfo.mjs';
|
|
7
7
|
import { useAuth } from './Auth.mjs';
|
|
8
8
|
import { useStrapiApp } from './StrapiApp.mjs';
|
|
@@ -10,7 +10,8 @@ import { useStrapiApp } from './StrapiApp.mjs';
|
|
|
10
10
|
/* -------------------------------------------------------------------------------------------------
|
|
11
11
|
* Context
|
|
12
12
|
* -----------------------------------------------------------------------------------------------*/ const TrackingContext = /*#__PURE__*/ React.createContext({
|
|
13
|
-
uuid: false
|
|
13
|
+
uuid: false,
|
|
14
|
+
isStrapiVersionReady: false
|
|
14
15
|
});
|
|
15
16
|
const TrackingProvider = ({ children })=>{
|
|
16
17
|
const token = useAuth('App', (state)=>state.token);
|
|
@@ -20,8 +21,14 @@ const TrackingProvider = ({ children })=>{
|
|
|
20
21
|
const { data } = useTelemetryPropertiesQuery(undefined, {
|
|
21
22
|
skip: !initData?.uuid || !token
|
|
22
23
|
});
|
|
24
|
+
const versionQueryEnabled = Boolean(initData?.uuid && token);
|
|
25
|
+
const { data: appInfo, isLoading: isLoadingAppInfo, isError: isInformationError } = useInformationQuery(undefined, {
|
|
26
|
+
skip: !versionQueryEnabled
|
|
27
|
+
});
|
|
28
|
+
const strapiVersion = appInfo?.strapiVersion;
|
|
29
|
+
const isStrapiVersionReady = Boolean(strapiVersion) || versionQueryEnabled && isInformationError;
|
|
23
30
|
React.useEffect(()=>{
|
|
24
|
-
if (uuid && data) {
|
|
31
|
+
if (uuid && data && !isLoadingAppInfo) {
|
|
25
32
|
const event = 'didInitializeAdministration';
|
|
26
33
|
try {
|
|
27
34
|
fetch(`${process.env.STRAPI_ANALYTICS_URL || 'https://analytics.strapi.io'}/api/v2/track`, {
|
|
@@ -34,7 +41,8 @@ const TrackingProvider = ({ children })=>{
|
|
|
34
41
|
groupProperties: {
|
|
35
42
|
...data,
|
|
36
43
|
projectId: uuid,
|
|
37
|
-
registeredWidgets: getAllWidgets().map((widget)=>widget.uid)
|
|
44
|
+
registeredWidgets: getAllWidgets().map((widget)=>widget.uid),
|
|
45
|
+
version: strapiVersion
|
|
38
46
|
}
|
|
39
47
|
}),
|
|
40
48
|
headers: {
|
|
@@ -49,14 +57,20 @@ const TrackingProvider = ({ children })=>{
|
|
|
49
57
|
}, [
|
|
50
58
|
data,
|
|
51
59
|
uuid,
|
|
52
|
-
getAllWidgets
|
|
60
|
+
getAllWidgets,
|
|
61
|
+
isLoadingAppInfo,
|
|
62
|
+
strapiVersion
|
|
53
63
|
]);
|
|
54
64
|
const value = React.useMemo(()=>({
|
|
55
65
|
uuid,
|
|
56
|
-
telemetryProperties: data
|
|
66
|
+
telemetryProperties: data,
|
|
67
|
+
strapiVersion,
|
|
68
|
+
isStrapiVersionReady
|
|
57
69
|
}), [
|
|
58
70
|
uuid,
|
|
59
|
-
data
|
|
71
|
+
data,
|
|
72
|
+
strapiVersion,
|
|
73
|
+
isStrapiVersionReady
|
|
60
74
|
]);
|
|
61
75
|
return /*#__PURE__*/ jsx(TrackingContext.Provider, {
|
|
62
76
|
value: value,
|
|
@@ -84,7 +98,7 @@ const TrackingProvider = ({ children })=>{
|
|
|
84
98
|
const deviceType = useDeviceType();
|
|
85
99
|
const deviceTypeRef = React.useRef(deviceType);
|
|
86
100
|
deviceTypeRef.current = deviceType;
|
|
87
|
-
const { uuid, telemetryProperties } = React.useContext(TrackingContext);
|
|
101
|
+
const { uuid, telemetryProperties, strapiVersion } = React.useContext(TrackingContext);
|
|
88
102
|
const userId = useAppInfo('useTracking', (state)=>state.userId);
|
|
89
103
|
const trackUsage = React.useCallback(async (event, properties)=>{
|
|
90
104
|
try {
|
|
@@ -101,7 +115,8 @@ const TrackingProvider = ({ children })=>{
|
|
|
101
115
|
groupProperties: {
|
|
102
116
|
...telemetryProperties,
|
|
103
117
|
projectId: uuid,
|
|
104
|
-
projectType: window.strapi.projectType
|
|
118
|
+
projectType: window.strapi.projectType,
|
|
119
|
+
version: strapiVersion
|
|
105
120
|
}
|
|
106
121
|
}, {
|
|
107
122
|
headers: {
|
|
@@ -116,6 +131,7 @@ const TrackingProvider = ({ children })=>{
|
|
|
116
131
|
}
|
|
117
132
|
return null;
|
|
118
133
|
}, [
|
|
134
|
+
strapiVersion,
|
|
119
135
|
telemetryProperties,
|
|
120
136
|
userId,
|
|
121
137
|
uuid
|
|
@@ -124,6 +140,9 @@ const TrackingProvider = ({ children })=>{
|
|
|
124
140
|
trackUsage
|
|
125
141
|
};
|
|
126
142
|
};
|
|
143
|
+
/**
|
|
144
|
+
* Internal readiness signal for events that must wait for the provider's version.
|
|
145
|
+
*/ const useStrapiVersionReady = ()=>React.useContext(TrackingContext).isStrapiVersionReady;
|
|
127
146
|
|
|
128
|
-
export { TrackingProvider, useTracking };
|
|
147
|
+
export { TrackingProvider, useStrapiVersionReady, useTracking };
|
|
129
148
|
//# sourceMappingURL=Tracking.mjs.map
|