@strapi/admin 5.27.0 → 5.28.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.
Files changed (81) hide show
  1. package/dist/admin/admin/src/components/DragLayer.js +67 -0
  2. package/dist/admin/admin/src/components/DragLayer.js.map +1 -0
  3. package/dist/admin/admin/src/components/DragLayer.mjs +64 -0
  4. package/dist/admin/admin/src/components/DragLayer.mjs.map +1 -0
  5. package/dist/admin/admin/src/components/GapDropZone.js +292 -0
  6. package/dist/admin/admin/src/components/GapDropZone.js.map +1 -0
  7. package/dist/admin/admin/src/components/GapDropZone.mjs +268 -0
  8. package/dist/admin/admin/src/components/GapDropZone.mjs.map +1 -0
  9. package/dist/admin/admin/src/components/ResizeIndicator.js +353 -0
  10. package/dist/admin/admin/src/components/ResizeIndicator.js.map +1 -0
  11. package/dist/admin/admin/src/components/ResizeIndicator.mjs +332 -0
  12. package/dist/admin/admin/src/components/ResizeIndicator.mjs.map +1 -0
  13. package/dist/admin/admin/src/components/WidgetRoot.js +216 -0
  14. package/dist/admin/admin/src/components/WidgetRoot.js.map +1 -0
  15. package/dist/admin/admin/src/components/WidgetRoot.mjs +195 -0
  16. package/dist/admin/admin/src/components/WidgetRoot.mjs.map +1 -0
  17. package/dist/admin/admin/src/features/Tracking.js.map +1 -1
  18. package/dist/admin/admin/src/features/Tracking.mjs.map +1 -1
  19. package/dist/admin/admin/src/features/Widgets.js +276 -0
  20. package/dist/admin/admin/src/features/Widgets.js.map +1 -0
  21. package/dist/admin/admin/src/features/Widgets.mjs +255 -0
  22. package/dist/admin/admin/src/features/Widgets.mjs.map +1 -0
  23. package/dist/admin/admin/src/hooks/useAPIErrorHandler.js +1 -1
  24. package/dist/admin/admin/src/hooks/useAPIErrorHandler.js.map +1 -1
  25. package/dist/admin/admin/src/hooks/useAPIErrorHandler.mjs +1 -1
  26. package/dist/admin/admin/src/hooks/useAPIErrorHandler.mjs.map +1 -1
  27. package/dist/admin/admin/src/pages/Home/HomePage.js +160 -91
  28. package/dist/admin/admin/src/pages/Home/HomePage.js.map +1 -1
  29. package/dist/admin/admin/src/pages/Home/HomePage.mjs +162 -93
  30. package/dist/admin/admin/src/pages/Home/HomePage.mjs.map +1 -1
  31. package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.js +189 -0
  32. package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.js.map +1 -0
  33. package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.mjs +168 -0
  34. package/dist/admin/admin/src/pages/Home/components/AddWidgetModal.mjs.map +1 -0
  35. package/dist/admin/admin/src/services/homepage.js +11 -4
  36. package/dist/admin/admin/src/services/homepage.js.map +1 -1
  37. package/dist/admin/admin/src/services/homepage.mjs +11 -4
  38. package/dist/admin/admin/src/services/homepage.mjs.map +1 -1
  39. package/dist/admin/admin/src/translations/en.json.js +6 -1
  40. package/dist/admin/admin/src/translations/en.json.js.map +1 -1
  41. package/dist/admin/admin/src/translations/en.json.mjs +6 -1
  42. package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
  43. package/dist/admin/admin/src/translations/uk.json.js +9 -9
  44. package/dist/admin/admin/src/translations/uk.json.mjs +9 -9
  45. package/dist/admin/admin/src/utils/resizeHandlers.js +109 -0
  46. package/dist/admin/admin/src/utils/resizeHandlers.js.map +1 -0
  47. package/dist/admin/admin/src/utils/resizeHandlers.mjs +100 -0
  48. package/dist/admin/admin/src/utils/resizeHandlers.mjs.map +1 -0
  49. package/dist/admin/admin/src/utils/widgetLayout.js +293 -0
  50. package/dist/admin/admin/src/utils/widgetLayout.js.map +1 -0
  51. package/dist/admin/admin/src/utils/widgetLayout.mjs +273 -0
  52. package/dist/admin/admin/src/utils/widgetLayout.mjs.map +1 -0
  53. package/dist/admin/src/components/DragLayer.d.ts +8 -4
  54. package/dist/admin/src/components/GapDropZone.d.ts +36 -0
  55. package/dist/admin/src/components/ResizeIndicator.d.ts +12 -0
  56. package/dist/admin/src/components/WidgetRoot.d.ts +14 -0
  57. package/dist/admin/src/features/Tracking.d.ts +1 -1
  58. package/dist/admin/src/features/Widgets.d.ts +29 -0
  59. package/dist/admin/src/pages/Home/HomePage.d.ts +4 -5
  60. package/dist/admin/src/pages/Home/components/AddWidgetModal.d.ts +10 -0
  61. package/dist/admin/src/services/homepage.d.ts +3 -3
  62. package/dist/admin/src/utils/resizeHandlers.d.ts +58 -0
  63. package/dist/admin/src/utils/widgetLayout.d.ts +78 -0
  64. package/dist/ee/server/src/controllers/authentication-utils/middlewares.d.ts.map +1 -1
  65. package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.js +4 -2
  66. package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.js.map +1 -1
  67. package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.mjs +4 -2
  68. package/dist/server/ee/server/src/controllers/authentication-utils/middlewares.mjs.map +1 -1
  69. package/dist/server/server/src/bootstrap.js +5 -0
  70. package/dist/server/server/src/bootstrap.js.map +1 -1
  71. package/dist/server/server/src/bootstrap.mjs +5 -0
  72. package/dist/server/server/src/bootstrap.mjs.map +1 -1
  73. package/dist/server/shared/utils/session-auth.js +4 -2
  74. package/dist/server/shared/utils/session-auth.js.map +1 -1
  75. package/dist/server/shared/utils/session-auth.mjs +4 -2
  76. package/dist/server/shared/utils/session-auth.mjs.map +1 -1
  77. package/dist/server/src/bootstrap.d.ts.map +1 -1
  78. package/dist/shared/contracts/homepage.d.ts +8 -4
  79. package/dist/shared/contracts/homepage.d.ts.map +1 -1
  80. package/dist/shared/utils/session-auth.d.ts.map +1 -1
  81. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"useAPIErrorHandler.js","sources":["../../../../../admin/src/hooks/useAPIErrorHandler.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { IntlFormatters, useIntl } from 'react-intl';\n\nimport { FetchError, ApiError } from '../utils/getFetchClient';\nimport { getPrefixedId } from '../utils/getPrefixedId';\nimport { NormalizeErrorOptions, normalizeAPIError } from '../utils/normalizeAPIError';\nimport { setIn } from '../utils/objects';\n\ninterface UnknownApiError {\n /**\n * The name of the ApiError, is always a static value.\n */\n name: 'UnknownError';\n /**\n * The error message.\n */\n message: string;\n /**\n * The error details.\n */\n details?: unknown;\n /**\n * The HTTP status code of the error.\n */\n status?: number;\n}\n\n/**\n * The last item is the fallback error SerializedError which\n * typically comes from redux-toolkit itself.\n */\ninterface SerializedError {\n /**\n * The name of the error.\n */\n name?: string;\n /**\n * The error message that explains what went wrong.\n */\n message?: string;\n /**\n * The stack trace of the error.\n */\n stack?: string;\n /**\n * A specific error code associated with the error.\n */\n code?: string;\n}\n\n/**\n * These are the types or errors we return\n * from the redux-toolkit data-fetching setup.\n */\ntype BaseQueryError = ApiError | UnknownApiError | SerializedError;\n\ninterface YupFormattedError {\n /**\n * An array representing the path to the field where the validation error occurred.\n */\n path: string[];\n /**\n * The error message describing the validation failure.\n */\n message: string;\n /**\n * The name of the error, typically identifies the type of validation error that occurred.\n */\n name: string;\n\n value: string;\n}\n\n/**\n * @public\n * @description The purpose of this hook is to offer a unified way to handle errors thrown by API endpoints, regardless of the type of error (`ValidationError`, `ApplicationErrror` ...)\nthat has been thrown.\n * @example\n * ```tsx\n * import * as React from 'react';\n * import { useFetchClient, useAPIErrorHandler, useNotification } from '@strapi/admin/admin';\n *\n * const MyComponent = () => {\n * const { get } = useFetchClient();\n * const { formatAPIError } = useAPIErrorHandler(getTrad);\n * const { toggleNotification } = useNotification();\n *\n * const handleDeleteItem = async () => {\n * try {\n * return await get('/admin');\n * } catch (error) {\n * toggleNotification({\n * type: 'danger',\n * message: formatAPIError(error),\n * });\n * }\n * };\n * return <button onClick={handleDeleteItem}>Delete item</button>;\n * };\n * ```\n */\nexport function useAPIErrorHandler(\n intlMessagePrefixCallback?: FormatAPIErrorOptions['intlMessagePrefixCallback']\n) {\n const { formatMessage } = useIntl();\n\n /**\n * @description This method try to normalize the passed error\n * and then call formatAPIError to stringify the ResponseObject\n * into a string. If it fails it will call formatFetchError and\n * return the error message.\n */\n const formatError = React.useCallback(\n (error: FetchError) => {\n // Try to normalize the passed error first. This will fail for e.g. network\n // errors which are thrown by fetchClient directly.\n try {\n const formattedErr = formatAPIError(error, { intlMessagePrefixCallback, formatMessage });\n\n if (!formattedErr) {\n return formatFetchError(error, { intlMessagePrefixCallback, formatMessage });\n }\n\n return formattedErr;\n } catch (_) {\n throw new Error('formatAPIError: Unknown error:', error);\n }\n },\n [formatMessage, intlMessagePrefixCallback]\n );\n\n return {\n /**\n * @alpha\n * Convert ValidationErrors from the API into an object that can be used by forms.\n */\n _unstableFormatValidationErrors: React.useCallback(\n (error: Extract<BaseQueryError, { name: 'ValidationError' }>): Record<string, string> => {\n if (typeof error.details === 'object' && error.details !== null) {\n if ('errors' in error.details && Array.isArray(error.details.errors)) {\n const validationErrors = error.details.errors as YupFormattedError[];\n\n return validationErrors.reduce((acc, err) => {\n const { path, message } = err;\n\n return setIn(acc, path.join('.'), message);\n }, {});\n } else {\n const details = error.details as Record<string, string[]>;\n\n return Object.keys(details).reduce((acc, key) => {\n const messages = details[key];\n\n return {\n ...acc,\n [key]: messages.join(', '),\n };\n }, {});\n }\n } else {\n return {};\n }\n },\n []\n ),\n /**\n * @alpha\n * This handles the errors given from `redux-toolkit`'s axios based baseQuery function.\n */\n _unstableFormatAPIError: React.useCallback(\n (error: BaseQueryError) => {\n const err = {\n response: {\n data: {\n error,\n },\n },\n } as FetchError;\n\n /**\n * There's a chance with SerializedErrors that the message is not set.\n * In that case we return a generic error message.\n */\n if (!error.message) {\n return 'Unknown error occured.';\n }\n\n return formatError(err);\n },\n [formatError]\n ),\n formatAPIError: formatError,\n };\n}\n\nfunction formatFetchError(\n error: FetchError,\n { intlMessagePrefixCallback, formatMessage }: FormatAPIErrorOptions\n) {\n const { code, message } = error;\n\n return formatMessage(\n {\n id: getPrefixedId(message, intlMessagePrefixCallback),\n defaultMessage: message,\n },\n {\n code,\n }\n );\n}\n\ntype FormatAPIErrorOptions = Partial<Pick<NormalizeErrorOptions, 'intlMessagePrefixCallback'>> &\n Pick<IntlFormatters, 'formatMessage'>;\n\n/**\n * @description This method stringifies the `ResponseObject` into\n * a string. If multiple errors are thrown by the API, which\n * happens e.g.in the case of a `ValidationError`, all errors\n * will bo concatenated into a single string.\n */\nfunction formatAPIError(\n error: FetchError,\n { formatMessage, intlMessagePrefixCallback }: FormatAPIErrorOptions\n) {\n if (!formatMessage) {\n throw new Error('The formatMessage callback is a mandatory argument.');\n }\n\n const normalizedError = normalizeAPIError(error, intlMessagePrefixCallback);\n\n if (!normalizedError) {\n return null;\n }\n\n if ('message' in normalizedError && normalizedError.message !== null) {\n return normalizedError.message;\n }\n\n // stringify multiple errors\n if ('errors' in normalizedError) {\n return normalizedError.errors\n .map(({ id, defaultMessage, values }) => formatMessage({ id, defaultMessage }, values))\n .join('\\n');\n }\n\n return formatMessage(normalizedError);\n}\n\nexport type { ApiError };\n"],"names":["useAPIErrorHandler","intlMessagePrefixCallback","formatMessage","useIntl","formatError","React","useCallback","error","formattedErr","formatAPIError","formatFetchError","_","Error","_unstableFormatValidationErrors","details","Array","isArray","errors","validationErrors","reduce","acc","err","path","message","setIn","join","Object","keys","key","messages","_unstableFormatAPIError","response","data","code","id","getPrefixedId","defaultMessage","normalizedError","normalizeAPIError","map","values"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA0EA;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BO,SAASA,kBAAAA,CACdC,yBAA8E,EAAA;IAE9E,MAAM,EAAEC,aAAa,EAAE,GAAGC,iBAAAA,EAAAA;AAE1B;;;;;AAKC,MACD,MAAMC,WAAAA,GAAcC,gBAAMC,CAAAA,WAAW,CACnC,CAACC,KAAAA,GAAAA;;;QAGC,IAAI;YACF,MAAMC,YAAAA,GAAeC,eAAeF,KAAO,EAAA;AAAEN,gBAAAA,yBAAAA;AAA2BC,gBAAAA;AAAc,aAAA,CAAA;AAEtF,YAAA,IAAI,CAACM,YAAc,EAAA;AACjB,gBAAA,OAAOE,iBAAiBH,KAAO,EAAA;AAAEN,oBAAAA,yBAAAA;AAA2BC,oBAAAA;AAAc,iBAAA,CAAA;AAC5E;YAEA,OAAOM,YAAAA;AACT,SAAA,CAAE,OAAOG,CAAG,EAAA;YACV,MAAM,IAAIC,MAAM,gCAAkCL,EAAAA,KAAAA,CAAAA;AACpD;KAEF,EAAA;AAACL,QAAAA,aAAAA;AAAeD,QAAAA;AAA0B,KAAA,CAAA;IAG5C,OAAO;AACL;;;AAGC,QACDY,+BAAiCR,EAAAA,gBAAAA,CAAMC,WAAW,CAChD,CAACC,KAAAA,GAAAA;YACC,IAAI,OAAOA,MAAMO,OAAO,KAAK,YAAYP,KAAMO,CAAAA,OAAO,KAAK,IAAM,EAAA;gBAC/D,IAAI,QAAA,IAAYP,KAAMO,CAAAA,OAAO,IAAIC,KAAAA,CAAMC,OAAO,CAACT,KAAMO,CAAAA,OAAO,CAACG,MAAM,CAAG,EAAA;AACpE,oBAAA,MAAMC,gBAAmBX,GAAAA,KAAAA,CAAMO,OAAO,CAACG,MAAM;AAE7C,oBAAA,OAAOC,gBAAiBC,CAAAA,MAAM,CAAC,CAACC,GAAKC,EAAAA,GAAAA,GAAAA;AACnC,wBAAA,MAAM,EAAEC,IAAI,EAAEC,OAAO,EAAE,GAAGF,GAAAA;AAE1B,wBAAA,OAAOG,aAAMJ,CAAAA,GAAAA,EAAKE,IAAKG,CAAAA,IAAI,CAAC,GAAMF,CAAAA,EAAAA,OAAAA,CAAAA;AACpC,qBAAA,EAAG,EAAC,CAAA;iBACC,MAAA;oBACL,MAAMT,OAAAA,GAAUP,MAAMO,OAAO;AAE7B,oBAAA,OAAOY,OAAOC,IAAI,CAACb,SAASK,MAAM,CAAC,CAACC,GAAKQ,EAAAA,GAAAA,GAAAA;wBACvC,MAAMC,QAAAA,GAAWf,OAAO,CAACc,GAAI,CAAA;wBAE7B,OAAO;AACL,4BAAA,GAAGR,GAAG;AACN,4BAAA,CAACQ,GAAI,GAAEC,QAASJ,CAAAA,IAAI,CAAC,IAAA;AACvB,yBAAA;AACF,qBAAA,EAAG,EAAC,CAAA;AACN;aACK,MAAA;AACL,gBAAA,OAAO,EAAC;AACV;AACF,SAAA,EACA,EAAE,CAAA;AAEJ;;;AAGC,QACDK,uBAAyBzB,EAAAA,gBAAAA,CAAMC,WAAW,CACxC,CAACC,KAAAA,GAAAA;AACC,YAAA,MAAMc,GAAM,GAAA;gBACVU,QAAU,EAAA;oBACRC,IAAM,EAAA;AACJzB,wBAAAA;AACF;AACF;AACF,aAAA;AAEA;;;AAGC,YACD,IAAI,CAACA,KAAMgB,CAAAA,OAAO,EAAE;gBAClB,OAAO,wBAAA;AACT;AAEA,YAAA,OAAOnB,WAAYiB,CAAAA,GAAAA,CAAAA;SAErB,EAAA;AAACjB,YAAAA;AAAY,SAAA,CAAA;QAEfK,cAAgBL,EAAAA;AAClB,KAAA;AACF;AAEA,SAASM,iBACPH,KAAiB,EACjB,EAAEN,yBAAyB,EAAEC,aAAa,EAAyB,EAAA;AAEnE,IAAA,MAAM,EAAE+B,IAAI,EAAEV,OAAO,EAAE,GAAGhB,KAAAA;AAE1B,IAAA,OAAOL,aACL,CAAA;AACEgC,QAAAA,EAAAA,EAAIC,4BAAcZ,OAAStB,EAAAA,yBAAAA,CAAAA;QAC3BmC,cAAgBb,EAAAA;KAElB,EAAA;AACEU,QAAAA;AACF,KAAA,CAAA;AAEJ;AAKA;;;;;IAMA,SAASxB,eACPF,KAAiB,EACjB,EAAEL,aAAa,EAAED,yBAAyB,EAAyB,EAAA;AAEnE,IAAA,IAAI,CAACC,aAAe,EAAA;AAClB,QAAA,MAAM,IAAIU,KAAM,CAAA,qDAAA,CAAA;AAClB;IAEA,MAAMyB,eAAAA,GAAkBC,oCAAkB/B,KAAON,EAAAA,yBAAAA,CAAAA;AAEjD,IAAA,IAAI,CAACoC,eAAiB,EAAA;QACpB,OAAO,IAAA;AACT;AAEA,IAAA,IAAI,SAAaA,IAAAA,eAAAA,IAAmBA,eAAgBd,CAAAA,OAAO,KAAK,IAAM,EAAA;AACpE,QAAA,OAAOc,gBAAgBd,OAAO;AAChC;;AAGA,IAAA,IAAI,YAAYc,eAAiB,EAAA;AAC/B,QAAA,OAAOA,eAAgBpB,CAAAA,MAAM,CAC1BsB,GAAG,CAAC,CAAC,EAAEL,EAAE,EAAEE,cAAc,EAAEI,MAAM,EAAE,GAAKtC,aAAc,CAAA;AAAEgC,gBAAAA,EAAAA;AAAIE,gBAAAA;aAAkBI,EAAAA,MAAAA,CAAAA,CAAAA,CAC9Ef,IAAI,CAAC,IAAA,CAAA;AACV;AAEA,IAAA,OAAOvB,aAAcmC,CAAAA,eAAAA,CAAAA;AACvB;;;;"}
1
+ {"version":3,"file":"useAPIErrorHandler.js","sources":["../../../../../admin/src/hooks/useAPIErrorHandler.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { IntlFormatters, useIntl } from 'react-intl';\n\nimport { FetchError, ApiError } from '../utils/getFetchClient';\nimport { getPrefixedId } from '../utils/getPrefixedId';\nimport { NormalizeErrorOptions, normalizeAPIError } from '../utils/normalizeAPIError';\nimport { setIn } from '../utils/objects';\n\ninterface UnknownApiError {\n /**\n * The name of the ApiError, is always a static value.\n */\n name: 'UnknownError';\n /**\n * The error message.\n */\n message: string;\n /**\n * The error details.\n */\n details?: unknown;\n /**\n * The HTTP status code of the error.\n */\n status?: number;\n}\n\n/**\n * The last item is the fallback error SerializedError which\n * typically comes from redux-toolkit itself.\n */\ninterface SerializedError {\n /**\n * The name of the error.\n */\n name?: string;\n /**\n * The error message that explains what went wrong.\n */\n message?: string;\n /**\n * The stack trace of the error.\n */\n stack?: string;\n /**\n * A specific error code associated with the error.\n */\n code?: string;\n}\n\n/**\n * These are the types or errors we return\n * from the redux-toolkit data-fetching setup.\n */\ntype BaseQueryError = ApiError | UnknownApiError | SerializedError;\n\ninterface YupFormattedError {\n /**\n * An array representing the path to the field where the validation error occurred.\n */\n path: string[];\n /**\n * The error message describing the validation failure.\n */\n message: string;\n /**\n * The name of the error, typically identifies the type of validation error that occurred.\n */\n name: string;\n\n value: string;\n}\n\n/**\n * @public\n * @description The purpose of this hook is to offer a unified way to handle errors thrown by API endpoints, regardless of the type of error (`ValidationError`, `ApplicationErrror` ...)\nthat has been thrown.\n * @example\n * ```tsx\n * import * as React from 'react';\n * import { useFetchClient, useAPIErrorHandler, useNotification } from '@strapi/admin/admin';\n *\n * const MyComponent = () => {\n * const { get } = useFetchClient();\n * const { formatAPIError } = useAPIErrorHandler(getTrad);\n * const { toggleNotification } = useNotification();\n *\n * const handleDeleteItem = async () => {\n * try {\n * return await get('/admin');\n * } catch (error) {\n * toggleNotification({\n * type: 'danger',\n * message: formatAPIError(error),\n * });\n * }\n * };\n * return <button onClick={handleDeleteItem}>Delete item</button>;\n * };\n * ```\n */\nexport function useAPIErrorHandler(\n intlMessagePrefixCallback?: FormatAPIErrorOptions['intlMessagePrefixCallback']\n) {\n const { formatMessage } = useIntl();\n\n /**\n * @description This method try to normalize the passed error\n * and then call formatAPIError to stringify the ResponseObject\n * into a string. If it fails it will call formatFetchError and\n * return the error message.\n */\n const formatError = React.useCallback(\n (error: FetchError) => {\n // Try to normalize the passed error first. This will fail for e.g. network\n // errors which are thrown by fetchClient directly.\n try {\n const formattedErr = formatAPIError(error, { intlMessagePrefixCallback, formatMessage });\n\n if (!formattedErr) {\n return formatFetchError(error, { intlMessagePrefixCallback, formatMessage });\n }\n\n return formattedErr;\n } catch (_) {\n throw new Error('formatAPIError: Unknown error:', error);\n }\n },\n [formatMessage, intlMessagePrefixCallback]\n );\n\n return {\n /**\n * @alpha\n * Convert ValidationErrors from the API into an object that can be used by forms.\n */\n _unstableFormatValidationErrors: React.useCallback(\n (error: Extract<BaseQueryError, { name: 'ValidationError' }>): Record<string, string> => {\n if (typeof error.details === 'object' && error.details !== null) {\n if ('errors' in error.details && Array.isArray(error.details.errors)) {\n const validationErrors = error.details.errors as YupFormattedError[];\n\n return validationErrors.reduce((acc, err) => {\n const { path, message } = err;\n\n return setIn(acc, path.join('.'), message);\n }, {});\n } else {\n const details = error.details as Record<string, string[]>;\n\n return Object.keys(details).reduce((acc, key) => {\n const messages = details[key];\n\n return {\n ...acc,\n [key]: messages.join(', '),\n };\n }, {});\n }\n } else {\n return {};\n }\n },\n []\n ),\n /**\n * @alpha\n * This handles the errors given from `redux-toolkit`'s axios based baseQuery function.\n */\n _unstableFormatAPIError: React.useCallback(\n (error: BaseQueryError) => {\n const err = {\n response: {\n data: {\n error,\n },\n },\n } as FetchError;\n\n /**\n * There's a chance with SerializedErrors that the message is not set.\n * In that case we return a generic error message.\n */\n if (!error.message) {\n return 'Unknown error occurred.';\n }\n\n return formatError(err);\n },\n [formatError]\n ),\n formatAPIError: formatError,\n };\n}\n\nfunction formatFetchError(\n error: FetchError,\n { intlMessagePrefixCallback, formatMessage }: FormatAPIErrorOptions\n) {\n const { code, message } = error;\n\n return formatMessage(\n {\n id: getPrefixedId(message, intlMessagePrefixCallback),\n defaultMessage: message,\n },\n {\n code,\n }\n );\n}\n\ntype FormatAPIErrorOptions = Partial<Pick<NormalizeErrorOptions, 'intlMessagePrefixCallback'>> &\n Pick<IntlFormatters, 'formatMessage'>;\n\n/**\n * @description This method stringifies the `ResponseObject` into\n * a string. If multiple errors are thrown by the API, which\n * happens e.g.in the case of a `ValidationError`, all errors\n * will bo concatenated into a single string.\n */\nfunction formatAPIError(\n error: FetchError,\n { formatMessage, intlMessagePrefixCallback }: FormatAPIErrorOptions\n) {\n if (!formatMessage) {\n throw new Error('The formatMessage callback is a mandatory argument.');\n }\n\n const normalizedError = normalizeAPIError(error, intlMessagePrefixCallback);\n\n if (!normalizedError) {\n return null;\n }\n\n if ('message' in normalizedError && normalizedError.message !== null) {\n return normalizedError.message;\n }\n\n // stringify multiple errors\n if ('errors' in normalizedError) {\n return normalizedError.errors\n .map(({ id, defaultMessage, values }) => formatMessage({ id, defaultMessage }, values))\n .join('\\n');\n }\n\n return formatMessage(normalizedError);\n}\n\nexport type { ApiError };\n"],"names":["useAPIErrorHandler","intlMessagePrefixCallback","formatMessage","useIntl","formatError","React","useCallback","error","formattedErr","formatAPIError","formatFetchError","_","Error","_unstableFormatValidationErrors","details","Array","isArray","errors","validationErrors","reduce","acc","err","path","message","setIn","join","Object","keys","key","messages","_unstableFormatAPIError","response","data","code","id","getPrefixedId","defaultMessage","normalizedError","normalizeAPIError","map","values"],"mappings":"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"}
@@ -101,7 +101,7 @@ that has been thrown.
101
101
  * There's a chance with SerializedErrors that the message is not set.
102
102
  * In that case we return a generic error message.
103
103
  */ if (!error.message) {
104
- return 'Unknown error occured.';
104
+ return 'Unknown error occurred.';
105
105
  }
106
106
  return formatError(err);
107
107
  }, [
@@ -1 +1 @@
1
- {"version":3,"file":"useAPIErrorHandler.mjs","sources":["../../../../../admin/src/hooks/useAPIErrorHandler.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { IntlFormatters, useIntl } from 'react-intl';\n\nimport { FetchError, ApiError } from '../utils/getFetchClient';\nimport { getPrefixedId } from '../utils/getPrefixedId';\nimport { NormalizeErrorOptions, normalizeAPIError } from '../utils/normalizeAPIError';\nimport { setIn } from '../utils/objects';\n\ninterface UnknownApiError {\n /**\n * The name of the ApiError, is always a static value.\n */\n name: 'UnknownError';\n /**\n * The error message.\n */\n message: string;\n /**\n * The error details.\n */\n details?: unknown;\n /**\n * The HTTP status code of the error.\n */\n status?: number;\n}\n\n/**\n * The last item is the fallback error SerializedError which\n * typically comes from redux-toolkit itself.\n */\ninterface SerializedError {\n /**\n * The name of the error.\n */\n name?: string;\n /**\n * The error message that explains what went wrong.\n */\n message?: string;\n /**\n * The stack trace of the error.\n */\n stack?: string;\n /**\n * A specific error code associated with the error.\n */\n code?: string;\n}\n\n/**\n * These are the types or errors we return\n * from the redux-toolkit data-fetching setup.\n */\ntype BaseQueryError = ApiError | UnknownApiError | SerializedError;\n\ninterface YupFormattedError {\n /**\n * An array representing the path to the field where the validation error occurred.\n */\n path: string[];\n /**\n * The error message describing the validation failure.\n */\n message: string;\n /**\n * The name of the error, typically identifies the type of validation error that occurred.\n */\n name: string;\n\n value: string;\n}\n\n/**\n * @public\n * @description The purpose of this hook is to offer a unified way to handle errors thrown by API endpoints, regardless of the type of error (`ValidationError`, `ApplicationErrror` ...)\nthat has been thrown.\n * @example\n * ```tsx\n * import * as React from 'react';\n * import { useFetchClient, useAPIErrorHandler, useNotification } from '@strapi/admin/admin';\n *\n * const MyComponent = () => {\n * const { get } = useFetchClient();\n * const { formatAPIError } = useAPIErrorHandler(getTrad);\n * const { toggleNotification } = useNotification();\n *\n * const handleDeleteItem = async () => {\n * try {\n * return await get('/admin');\n * } catch (error) {\n * toggleNotification({\n * type: 'danger',\n * message: formatAPIError(error),\n * });\n * }\n * };\n * return <button onClick={handleDeleteItem}>Delete item</button>;\n * };\n * ```\n */\nexport function useAPIErrorHandler(\n intlMessagePrefixCallback?: FormatAPIErrorOptions['intlMessagePrefixCallback']\n) {\n const { formatMessage } = useIntl();\n\n /**\n * @description This method try to normalize the passed error\n * and then call formatAPIError to stringify the ResponseObject\n * into a string. If it fails it will call formatFetchError and\n * return the error message.\n */\n const formatError = React.useCallback(\n (error: FetchError) => {\n // Try to normalize the passed error first. This will fail for e.g. network\n // errors which are thrown by fetchClient directly.\n try {\n const formattedErr = formatAPIError(error, { intlMessagePrefixCallback, formatMessage });\n\n if (!formattedErr) {\n return formatFetchError(error, { intlMessagePrefixCallback, formatMessage });\n }\n\n return formattedErr;\n } catch (_) {\n throw new Error('formatAPIError: Unknown error:', error);\n }\n },\n [formatMessage, intlMessagePrefixCallback]\n );\n\n return {\n /**\n * @alpha\n * Convert ValidationErrors from the API into an object that can be used by forms.\n */\n _unstableFormatValidationErrors: React.useCallback(\n (error: Extract<BaseQueryError, { name: 'ValidationError' }>): Record<string, string> => {\n if (typeof error.details === 'object' && error.details !== null) {\n if ('errors' in error.details && Array.isArray(error.details.errors)) {\n const validationErrors = error.details.errors as YupFormattedError[];\n\n return validationErrors.reduce((acc, err) => {\n const { path, message } = err;\n\n return setIn(acc, path.join('.'), message);\n }, {});\n } else {\n const details = error.details as Record<string, string[]>;\n\n return Object.keys(details).reduce((acc, key) => {\n const messages = details[key];\n\n return {\n ...acc,\n [key]: messages.join(', '),\n };\n }, {});\n }\n } else {\n return {};\n }\n },\n []\n ),\n /**\n * @alpha\n * This handles the errors given from `redux-toolkit`'s axios based baseQuery function.\n */\n _unstableFormatAPIError: React.useCallback(\n (error: BaseQueryError) => {\n const err = {\n response: {\n data: {\n error,\n },\n },\n } as FetchError;\n\n /**\n * There's a chance with SerializedErrors that the message is not set.\n * In that case we return a generic error message.\n */\n if (!error.message) {\n return 'Unknown error occured.';\n }\n\n return formatError(err);\n },\n [formatError]\n ),\n formatAPIError: formatError,\n };\n}\n\nfunction formatFetchError(\n error: FetchError,\n { intlMessagePrefixCallback, formatMessage }: FormatAPIErrorOptions\n) {\n const { code, message } = error;\n\n return formatMessage(\n {\n id: getPrefixedId(message, intlMessagePrefixCallback),\n defaultMessage: message,\n },\n {\n code,\n }\n );\n}\n\ntype FormatAPIErrorOptions = Partial<Pick<NormalizeErrorOptions, 'intlMessagePrefixCallback'>> &\n Pick<IntlFormatters, 'formatMessage'>;\n\n/**\n * @description This method stringifies the `ResponseObject` into\n * a string. If multiple errors are thrown by the API, which\n * happens e.g.in the case of a `ValidationError`, all errors\n * will bo concatenated into a single string.\n */\nfunction formatAPIError(\n error: FetchError,\n { formatMessage, intlMessagePrefixCallback }: FormatAPIErrorOptions\n) {\n if (!formatMessage) {\n throw new Error('The formatMessage callback is a mandatory argument.');\n }\n\n const normalizedError = normalizeAPIError(error, intlMessagePrefixCallback);\n\n if (!normalizedError) {\n return null;\n }\n\n if ('message' in normalizedError && normalizedError.message !== null) {\n return normalizedError.message;\n }\n\n // stringify multiple errors\n if ('errors' in normalizedError) {\n return normalizedError.errors\n .map(({ id, defaultMessage, values }) => formatMessage({ id, defaultMessage }, values))\n .join('\\n');\n }\n\n return formatMessage(normalizedError);\n}\n\nexport type { ApiError };\n"],"names":["useAPIErrorHandler","intlMessagePrefixCallback","formatMessage","useIntl","formatError","React","useCallback","error","formattedErr","formatAPIError","formatFetchError","_","Error","_unstableFormatValidationErrors","details","Array","isArray","errors","validationErrors","reduce","acc","err","path","message","setIn","join","Object","keys","key","messages","_unstableFormatAPIError","response","data","code","id","getPrefixedId","defaultMessage","normalizedError","normalizeAPIError","map","values"],"mappings":";;;;;;AA0EA;;;;;;;;;;;;;;;;;;;;;;;;;;;IA4BO,SAASA,kBAAAA,CACdC,yBAA8E,EAAA;IAE9E,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;AAE1B;;;;;AAKC,MACD,MAAMC,WAAAA,GAAcC,KAAMC,CAAAA,WAAW,CACnC,CAACC,KAAAA,GAAAA;;;QAGC,IAAI;YACF,MAAMC,YAAAA,GAAeC,eAAeF,KAAO,EAAA;AAAEN,gBAAAA,yBAAAA;AAA2BC,gBAAAA;AAAc,aAAA,CAAA;AAEtF,YAAA,IAAI,CAACM,YAAc,EAAA;AACjB,gBAAA,OAAOE,iBAAiBH,KAAO,EAAA;AAAEN,oBAAAA,yBAAAA;AAA2BC,oBAAAA;AAAc,iBAAA,CAAA;AAC5E;YAEA,OAAOM,YAAAA;AACT,SAAA,CAAE,OAAOG,CAAG,EAAA;YACV,MAAM,IAAIC,MAAM,gCAAkCL,EAAAA,KAAAA,CAAAA;AACpD;KAEF,EAAA;AAACL,QAAAA,aAAAA;AAAeD,QAAAA;AAA0B,KAAA,CAAA;IAG5C,OAAO;AACL;;;AAGC,QACDY,+BAAiCR,EAAAA,KAAAA,CAAMC,WAAW,CAChD,CAACC,KAAAA,GAAAA;YACC,IAAI,OAAOA,MAAMO,OAAO,KAAK,YAAYP,KAAMO,CAAAA,OAAO,KAAK,IAAM,EAAA;gBAC/D,IAAI,QAAA,IAAYP,KAAMO,CAAAA,OAAO,IAAIC,KAAAA,CAAMC,OAAO,CAACT,KAAMO,CAAAA,OAAO,CAACG,MAAM,CAAG,EAAA;AACpE,oBAAA,MAAMC,gBAAmBX,GAAAA,KAAAA,CAAMO,OAAO,CAACG,MAAM;AAE7C,oBAAA,OAAOC,gBAAiBC,CAAAA,MAAM,CAAC,CAACC,GAAKC,EAAAA,GAAAA,GAAAA;AACnC,wBAAA,MAAM,EAAEC,IAAI,EAAEC,OAAO,EAAE,GAAGF,GAAAA;AAE1B,wBAAA,OAAOG,KAAMJ,CAAAA,GAAAA,EAAKE,IAAKG,CAAAA,IAAI,CAAC,GAAMF,CAAAA,EAAAA,OAAAA,CAAAA;AACpC,qBAAA,EAAG,EAAC,CAAA;iBACC,MAAA;oBACL,MAAMT,OAAAA,GAAUP,MAAMO,OAAO;AAE7B,oBAAA,OAAOY,OAAOC,IAAI,CAACb,SAASK,MAAM,CAAC,CAACC,GAAKQ,EAAAA,GAAAA,GAAAA;wBACvC,MAAMC,QAAAA,GAAWf,OAAO,CAACc,GAAI,CAAA;wBAE7B,OAAO;AACL,4BAAA,GAAGR,GAAG;AACN,4BAAA,CAACQ,GAAI,GAAEC,QAASJ,CAAAA,IAAI,CAAC,IAAA;AACvB,yBAAA;AACF,qBAAA,EAAG,EAAC,CAAA;AACN;aACK,MAAA;AACL,gBAAA,OAAO,EAAC;AACV;AACF,SAAA,EACA,EAAE,CAAA;AAEJ;;;AAGC,QACDK,uBAAyBzB,EAAAA,KAAAA,CAAMC,WAAW,CACxC,CAACC,KAAAA,GAAAA;AACC,YAAA,MAAMc,GAAM,GAAA;gBACVU,QAAU,EAAA;oBACRC,IAAM,EAAA;AACJzB,wBAAAA;AACF;AACF;AACF,aAAA;AAEA;;;AAGC,YACD,IAAI,CAACA,KAAMgB,CAAAA,OAAO,EAAE;gBAClB,OAAO,wBAAA;AACT;AAEA,YAAA,OAAOnB,WAAYiB,CAAAA,GAAAA,CAAAA;SAErB,EAAA;AAACjB,YAAAA;AAAY,SAAA,CAAA;QAEfK,cAAgBL,EAAAA;AAClB,KAAA;AACF;AAEA,SAASM,iBACPH,KAAiB,EACjB,EAAEN,yBAAyB,EAAEC,aAAa,EAAyB,EAAA;AAEnE,IAAA,MAAM,EAAE+B,IAAI,EAAEV,OAAO,EAAE,GAAGhB,KAAAA;AAE1B,IAAA,OAAOL,aACL,CAAA;AACEgC,QAAAA,EAAAA,EAAIC,cAAcZ,OAAStB,EAAAA,yBAAAA,CAAAA;QAC3BmC,cAAgBb,EAAAA;KAElB,EAAA;AACEU,QAAAA;AACF,KAAA,CAAA;AAEJ;AAKA;;;;;IAMA,SAASxB,eACPF,KAAiB,EACjB,EAAEL,aAAa,EAAED,yBAAyB,EAAyB,EAAA;AAEnE,IAAA,IAAI,CAACC,aAAe,EAAA;AAClB,QAAA,MAAM,IAAIU,KAAM,CAAA,qDAAA,CAAA;AAClB;IAEA,MAAMyB,eAAAA,GAAkBC,kBAAkB/B,KAAON,EAAAA,yBAAAA,CAAAA;AAEjD,IAAA,IAAI,CAACoC,eAAiB,EAAA;QACpB,OAAO,IAAA;AACT;AAEA,IAAA,IAAI,SAAaA,IAAAA,eAAAA,IAAmBA,eAAgBd,CAAAA,OAAO,KAAK,IAAM,EAAA;AACpE,QAAA,OAAOc,gBAAgBd,OAAO;AAChC;;AAGA,IAAA,IAAI,YAAYc,eAAiB,EAAA;AAC/B,QAAA,OAAOA,eAAgBpB,CAAAA,MAAM,CAC1BsB,GAAG,CAAC,CAAC,EAAEL,EAAE,EAAEE,cAAc,EAAEI,MAAM,EAAE,GAAKtC,aAAc,CAAA;AAAEgC,gBAAAA,EAAAA;AAAIE,gBAAAA;aAAkBI,EAAAA,MAAAA,CAAAA,CAAAA,CAC9Ef,IAAI,CAAC,IAAA,CAAA;AACV;AAEA,IAAA,OAAOvB,aAAcmC,CAAAA,eAAAA,CAAAA;AACvB;;;;"}
1
+ {"version":3,"file":"useAPIErrorHandler.mjs","sources":["../../../../../admin/src/hooks/useAPIErrorHandler.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { IntlFormatters, useIntl } from 'react-intl';\n\nimport { FetchError, ApiError } from '../utils/getFetchClient';\nimport { getPrefixedId } from '../utils/getPrefixedId';\nimport { NormalizeErrorOptions, normalizeAPIError } from '../utils/normalizeAPIError';\nimport { setIn } from '../utils/objects';\n\ninterface UnknownApiError {\n /**\n * The name of the ApiError, is always a static value.\n */\n name: 'UnknownError';\n /**\n * The error message.\n */\n message: string;\n /**\n * The error details.\n */\n details?: unknown;\n /**\n * The HTTP status code of the error.\n */\n status?: number;\n}\n\n/**\n * The last item is the fallback error SerializedError which\n * typically comes from redux-toolkit itself.\n */\ninterface SerializedError {\n /**\n * The name of the error.\n */\n name?: string;\n /**\n * The error message that explains what went wrong.\n */\n message?: string;\n /**\n * The stack trace of the error.\n */\n stack?: string;\n /**\n * A specific error code associated with the error.\n */\n code?: string;\n}\n\n/**\n * These are the types or errors we return\n * from the redux-toolkit data-fetching setup.\n */\ntype BaseQueryError = ApiError | UnknownApiError | SerializedError;\n\ninterface YupFormattedError {\n /**\n * An array representing the path to the field where the validation error occurred.\n */\n path: string[];\n /**\n * The error message describing the validation failure.\n */\n message: string;\n /**\n * The name of the error, typically identifies the type of validation error that occurred.\n */\n name: string;\n\n value: string;\n}\n\n/**\n * @public\n * @description The purpose of this hook is to offer a unified way to handle errors thrown by API endpoints, regardless of the type of error (`ValidationError`, `ApplicationErrror` ...)\nthat has been thrown.\n * @example\n * ```tsx\n * import * as React from 'react';\n * import { useFetchClient, useAPIErrorHandler, useNotification } from '@strapi/admin/admin';\n *\n * const MyComponent = () => {\n * const { get } = useFetchClient();\n * const { formatAPIError } = useAPIErrorHandler(getTrad);\n * const { toggleNotification } = useNotification();\n *\n * const handleDeleteItem = async () => {\n * try {\n * return await get('/admin');\n * } catch (error) {\n * toggleNotification({\n * type: 'danger',\n * message: formatAPIError(error),\n * });\n * }\n * };\n * return <button onClick={handleDeleteItem}>Delete item</button>;\n * };\n * ```\n */\nexport function useAPIErrorHandler(\n intlMessagePrefixCallback?: FormatAPIErrorOptions['intlMessagePrefixCallback']\n) {\n const { formatMessage } = useIntl();\n\n /**\n * @description This method try to normalize the passed error\n * and then call formatAPIError to stringify the ResponseObject\n * into a string. If it fails it will call formatFetchError and\n * return the error message.\n */\n const formatError = React.useCallback(\n (error: FetchError) => {\n // Try to normalize the passed error first. This will fail for e.g. network\n // errors which are thrown by fetchClient directly.\n try {\n const formattedErr = formatAPIError(error, { intlMessagePrefixCallback, formatMessage });\n\n if (!formattedErr) {\n return formatFetchError(error, { intlMessagePrefixCallback, formatMessage });\n }\n\n return formattedErr;\n } catch (_) {\n throw new Error('formatAPIError: Unknown error:', error);\n }\n },\n [formatMessage, intlMessagePrefixCallback]\n );\n\n return {\n /**\n * @alpha\n * Convert ValidationErrors from the API into an object that can be used by forms.\n */\n _unstableFormatValidationErrors: React.useCallback(\n (error: Extract<BaseQueryError, { name: 'ValidationError' }>): Record<string, string> => {\n if (typeof error.details === 'object' && error.details !== null) {\n if ('errors' in error.details && Array.isArray(error.details.errors)) {\n const validationErrors = error.details.errors as YupFormattedError[];\n\n return validationErrors.reduce((acc, err) => {\n const { path, message } = err;\n\n return setIn(acc, path.join('.'), message);\n }, {});\n } else {\n const details = error.details as Record<string, string[]>;\n\n return Object.keys(details).reduce((acc, key) => {\n const messages = details[key];\n\n return {\n ...acc,\n [key]: messages.join(', '),\n };\n }, {});\n }\n } else {\n return {};\n }\n },\n []\n ),\n /**\n * @alpha\n * This handles the errors given from `redux-toolkit`'s axios based baseQuery function.\n */\n _unstableFormatAPIError: React.useCallback(\n (error: BaseQueryError) => {\n const err = {\n response: {\n data: {\n error,\n },\n },\n } as FetchError;\n\n /**\n * There's a chance with SerializedErrors that the message is not set.\n * In that case we return a generic error message.\n */\n if (!error.message) {\n return 'Unknown error occurred.';\n }\n\n return formatError(err);\n },\n [formatError]\n ),\n formatAPIError: formatError,\n };\n}\n\nfunction formatFetchError(\n error: FetchError,\n { intlMessagePrefixCallback, formatMessage }: FormatAPIErrorOptions\n) {\n const { code, message } = error;\n\n return formatMessage(\n {\n id: getPrefixedId(message, intlMessagePrefixCallback),\n defaultMessage: message,\n },\n {\n code,\n }\n );\n}\n\ntype FormatAPIErrorOptions = Partial<Pick<NormalizeErrorOptions, 'intlMessagePrefixCallback'>> &\n Pick<IntlFormatters, 'formatMessage'>;\n\n/**\n * @description This method stringifies the `ResponseObject` into\n * a string. If multiple errors are thrown by the API, which\n * happens e.g.in the case of a `ValidationError`, all errors\n * will bo concatenated into a single string.\n */\nfunction formatAPIError(\n error: FetchError,\n { formatMessage, intlMessagePrefixCallback }: FormatAPIErrorOptions\n) {\n if (!formatMessage) {\n throw new Error('The formatMessage callback is a mandatory argument.');\n }\n\n const normalizedError = normalizeAPIError(error, intlMessagePrefixCallback);\n\n if (!normalizedError) {\n return null;\n }\n\n if ('message' in normalizedError && normalizedError.message !== null) {\n return normalizedError.message;\n }\n\n // stringify multiple errors\n if ('errors' in normalizedError) {\n return normalizedError.errors\n .map(({ id, defaultMessage, values }) => formatMessage({ id, defaultMessage }, values))\n .join('\\n');\n }\n\n return formatMessage(normalizedError);\n}\n\nexport type { ApiError };\n"],"names":["useAPIErrorHandler","intlMessagePrefixCallback","formatMessage","useIntl","formatError","React","useCallback","error","formattedErr","formatAPIError","formatFetchError","_","Error","_unstableFormatValidationErrors","details","Array","isArray","errors","validationErrors","reduce","acc","err","path","message","setIn","join","Object","keys","key","messages","_unstableFormatAPIError","response","data","code","id","getPrefixedId","defaultMessage","normalizedError","normalizeAPIError","map","values"],"mappings":"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"}
@@ -5,17 +5,24 @@ var React = require('react');
5
5
  var designSystem = require('@strapi/design-system');
6
6
  var icons = require('@strapi/icons');
7
7
  var reactIntl = require('react-intl');
8
- var reactRouterDom = require('react-router-dom');
8
+ var styled = require('styled-components');
9
+ var DragLayer = require('../../components/DragLayer.js');
10
+ var GapDropZone = require('../../components/GapDropZone.js');
9
11
  var Overview = require('../../components/GuidedTour/Overview.js');
10
12
  var Layout = require('../../components/Layouts/Layout.js');
11
13
  var PageHelpers = require('../../components/PageHelpers.js');
14
+ var ResizeIndicator = require('../../components/ResizeIndicator.js');
12
15
  var WidgetHelpers = require('../../components/WidgetHelpers.js');
16
+ var WidgetRoot = require('../../components/WidgetRoot.js');
13
17
  require('../../services/admin.js');
14
18
  var useEnterprise = require('../../hooks/useEnterprise.js');
15
19
  require('../../../../ee/admin/src/services/ai.js');
16
20
  var Auth = require('../../features/Auth.js');
17
21
  var StrapiApp = require('../../features/StrapiApp.js');
18
- var Tracking = require('../../features/Tracking.js');
22
+ var Widgets = require('../../features/Widgets.js');
23
+ var homepage = require('../../services/homepage.js');
24
+ var widgetLayout = require('../../utils/widgetLayout.js');
25
+ var AddWidgetModal = require('./components/AddWidgetModal.js');
19
26
  var FreeTrialEndedModal = require('./components/FreeTrialEndedModal.js');
20
27
  var FreeTrialWelcomeModal = require('./components/FreeTrialWelcomeModal.js');
21
28
 
@@ -38,79 +45,18 @@ function _interopNamespaceDefault(e) {
38
45
 
39
46
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
40
47
 
41
- const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
42
- const { trackUsage } = Tracking.useTracking();
43
- const { formatMessage } = reactIntl.useIntl();
44
- const id = React__namespace.useId();
45
- const Icon = icon;
46
- const handleClickOnLink = ()=>{
47
- trackUsage('didOpenHomeWidgetLink', {
48
- widgetUID: uid
49
- });
50
- };
51
- return /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
52
- width: "100%",
53
- hasRadius: true,
54
- direction: "column",
55
- alignItems: "flex-start",
56
- background: "neutral0",
57
- borderColor: "neutral150",
58
- shadow: "tableShadow",
59
- tag: "section",
60
- gap: 4,
61
- padding: 6,
62
- "aria-labelledby": id,
63
- children: [
64
- /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
65
- direction: "row",
66
- gap: 2,
67
- justifyContent: "space-between",
68
- width: "100%",
69
- tag: "header",
70
- children: [
71
- /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
72
- gap: 2,
73
- children: [
74
- /*#__PURE__*/ jsxRuntime.jsx(Icon, {
75
- fill: "neutral500",
76
- "aria-hidden": true
77
- }),
78
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
79
- textColor: "neutral500",
80
- variant: "sigma",
81
- tag: "h2",
82
- id: id,
83
- children: formatMessage(title)
84
- })
85
- ]
86
- }),
87
- link && /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
88
- tag: reactRouterDom.Link,
89
- variant: "omega",
90
- textColor: "primary600",
91
- style: {
92
- textDecoration: 'none'
93
- },
94
- textAlign: "right",
95
- to: link.href,
96
- onClick: handleClickOnLink,
97
- children: formatMessage(link.label)
98
- })
99
- ]
100
- }),
101
- /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
102
- width: "100%",
103
- height: "261px",
104
- overflow: "auto",
105
- tag: "main",
106
- children: children
107
- })
108
- ]
109
- });
110
- };
48
+ // Styled wrapper for the drag preview
49
+ const DragPreviewWrapper = styled.styled.div`
50
+ max-width: ${(props)=>props.$maxWidth};
51
+ overflow: hidden;
52
+ opacity: 0.9;
53
+ border: 2px solid ${({ theme })=>theme.colors.primary500};
54
+ border-radius: ${({ theme })=>theme.borderRadius};
55
+ pointer-events: none;
56
+ `;
111
57
  /* -------------------------------------------------------------------------------------------------
112
58
  * UnstableHomePageCe
113
- * -----------------------------------------------------------------------------------------------*/ const WidgetComponent = ({ component })=>{
59
+ * -----------------------------------------------------------------------------------------------*/ const WidgetComponent = ({ component, columnWidth })=>{
114
60
  const [loadedComponent, setLoadedComponent] = React__namespace.useState(null);
115
61
  React__namespace.useEffect(()=>{
116
62
  const loadComponent = async ()=>{
@@ -125,7 +71,11 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
125
71
  if (!Component) {
126
72
  return /*#__PURE__*/ jsxRuntime.jsx(WidgetHelpers.Widget.Loading, {});
127
73
  }
128
- return /*#__PURE__*/ jsxRuntime.jsx(Component, {});
74
+ return /*#__PURE__*/ jsxRuntime.jsx(Component, {
75
+ ...{
76
+ columnWidth
77
+ }
78
+ });
129
79
  };
130
80
  /* -------------------------------------------------------------------------------------------------
131
81
  * HomePageCE
@@ -135,8 +85,16 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
135
85
  const displayName = user?.firstname ?? user?.username ?? user?.email;
136
86
  const getAllWidgets = StrapiApp.useStrapiApp('UnstableHomepageCe', (state)=>state.widgets.getAll);
137
87
  const checkUserHasPermissions = Auth.useAuth('WidgetRoot', (state)=>state.checkUserHasPermissions);
88
+ const { data: homepageLayout, isLoading: _isLoadingLayout } = homepage.useGetHomepageLayoutQuery();
138
89
  const [filteredWidgets, setFilteredWidgets] = React__namespace.useState([]);
90
+ const [allAvailableWidgets, setAllAvailableWidgets] = React__namespace.useState([]);
139
91
  const [loading, setLoading] = React__namespace.useState(true);
92
+ const [isAddWidgetModalOpen, setIsAddWidgetModalOpen] = React__namespace.useState(false);
93
+ // Use custom hook for widget management
94
+ const { findWidget, deleteWidget, addWidget, moveWidget, columnWidths, setColumnWidths, handleWidgetResize, saveLayout, isDraggingWidget, draggedWidgetId, handleDragStart, handleDragEnd } = Widgets.useWidgets({
95
+ filteredWidgets,
96
+ setFilteredWidgets
97
+ });
140
98
  React__namespace.useEffect(()=>{
141
99
  const checkWidgetsPermissions = async ()=>{
142
100
  const allWidgets = getAllWidgets();
@@ -145,7 +103,8 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
145
103
  const matchingPermissions = await checkUserHasPermissions(widget.permissions);
146
104
  return matchingPermissions.length >= widget.permissions.length;
147
105
  }));
148
- setFilteredWidgets(allWidgets.filter((_, i)=>authorizedWidgets[i]));
106
+ const authorizedWidgetsList = allWidgets.filter((_, i)=>authorizedWidgets[i]);
107
+ setAllAvailableWidgets(authorizedWidgetsList);
149
108
  setLoading(false);
150
109
  };
151
110
  checkWidgetsPermissions();
@@ -153,6 +112,42 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
153
112
  checkUserHasPermissions,
154
113
  getAllWidgets
155
114
  ]);
115
+ React__namespace.useEffect(()=>{
116
+ if (allAvailableWidgets.length === 0) return;
117
+ // If user has customized the homepage layout, apply it
118
+ if (homepageLayout && homepageLayout.widgets) {
119
+ const { filteredWidgets, widths: homepageWidths } = widgetLayout.applyHomepageLayout(allAvailableWidgets, homepageLayout);
120
+ setFilteredWidgets(filteredWidgets);
121
+ setColumnWidths(homepageWidths);
122
+ } else {
123
+ // Set default layout when no custom layout exists
124
+ setFilteredWidgets(allAvailableWidgets);
125
+ setColumnWidths(widgetLayout.createDefaultWidgetWidths(allAvailableWidgets));
126
+ }
127
+ }, [
128
+ homepageLayout,
129
+ allAvailableWidgets,
130
+ setColumnWidths
131
+ ]);
132
+ const widgetLayout$1 = React__namespace.useMemo(()=>{
133
+ return filteredWidgets.map((widget, index)=>{
134
+ const rightWidgetId = filteredWidgets[index + 1]?.uid;
135
+ const widgetWidth = widgetLayout.getWidgetWidth(columnWidths, widget.uid);
136
+ const rightWidgetWidth = widgetLayout.getWidgetWidth(columnWidths, rightWidgetId);
137
+ return {
138
+ widget,
139
+ index,
140
+ isLastInRow: widgetLayout.isLastWidgetInRow(index, filteredWidgets, columnWidths),
141
+ rightWidgetId,
142
+ widgetWidth,
143
+ rightWidgetWidth,
144
+ canResize: rightWidgetId && widgetLayout.canResizeBetweenWidgets(widget.uid, rightWidgetId, columnWidths, filteredWidgets)
145
+ };
146
+ });
147
+ }, [
148
+ filteredWidgets,
149
+ columnWidths
150
+ ]);
156
151
  return /*#__PURE__*/ jsxRuntime.jsx(Layout.Layouts.Root, {
157
152
  children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Main, {
158
153
  children: [
@@ -172,15 +167,33 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
172
167
  subtitle: formatMessage({
173
168
  id: 'HomePage.header.subtitle',
174
169
  defaultMessage: 'Welcome to your administration panel'
170
+ }),
171
+ primaryAction: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Button, {
172
+ variant: "tertiary",
173
+ size: "S",
174
+ startIcon: /*#__PURE__*/ jsxRuntime.jsx(icons.Plus, {}),
175
+ onClick: ()=>setIsAddWidgetModalOpen(true),
176
+ children: formatMessage({
177
+ id: 'HomePage.addWidget.button',
178
+ defaultMessage: 'Add Widget'
179
+ })
175
180
  })
176
181
  }),
177
182
  /*#__PURE__*/ jsxRuntime.jsx(FreeTrialWelcomeModal.FreeTrialWelcomeModal, {}),
178
183
  /*#__PURE__*/ jsxRuntime.jsx(FreeTrialEndedModal.FreeTrialEndedModal, {}),
184
+ /*#__PURE__*/ jsxRuntime.jsx(AddWidgetModal.AddWidgetModal, {
185
+ isOpen: isAddWidgetModalOpen,
186
+ onClose: ()=>setIsAddWidgetModalOpen(false),
187
+ onAddWidget: addWidget,
188
+ currentWidgets: filteredWidgets,
189
+ availableWidgets: allAvailableWidgets
190
+ }),
179
191
  /*#__PURE__*/ jsxRuntime.jsx(Layout.Layouts.Content, {
180
192
  children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Flex, {
181
193
  direction: "column",
182
194
  alignItems: "stretch",
183
195
  gap: 8,
196
+ paddingBottom: 10,
184
197
  children: [
185
198
  /*#__PURE__*/ jsxRuntime.jsx(Overview.GuidedTourHomepageOverview, {}),
186
199
  loading ? /*#__PURE__*/ jsxRuntime.jsx(designSystem.Box, {
@@ -190,24 +203,80 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
190
203
  right: 0,
191
204
  bottom: 0,
192
205
  children: /*#__PURE__*/ jsxRuntime.jsx(PageHelpers.Page.Loading, {})
193
- }) : /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
194
- gap: 5,
195
- children: filteredWidgets.map((widget)=>/*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
196
- col: 6,
197
- s: 12,
198
- children: /*#__PURE__*/ jsxRuntime.jsx(WidgetRoot, {
199
- title: widget.title,
200
- icon: widget.icon,
201
- link: widget.link,
202
- uid: widget.uid,
203
- children: /*#__PURE__*/ jsxRuntime.jsx(WidgetComponent, {
204
- component: widget.component
205
- })
206
- })
207
- }, widget.uid))
206
+ }) : /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Box, {
207
+ position: "relative",
208
+ [widgetLayout.WIDGET_DATA_ATTRIBUTES.GRID_CONTAINER]: true,
209
+ children: [
210
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Root, {
211
+ gap: 5,
212
+ children: widgetLayout$1.map(({ widget, isLastInRow, rightWidgetId, widgetWidth, rightWidgetWidth, canResize })=>/*#__PURE__*/ jsxRuntime.jsxs(React__namespace.Fragment, {
213
+ children: [
214
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Grid.Item, {
215
+ col: widgetWidth,
216
+ s: 12,
217
+ children: /*#__PURE__*/ jsxRuntime.jsx(WidgetRoot.WidgetRoot, {
218
+ uid: widget.uid,
219
+ title: widget.title,
220
+ icon: widget.icon,
221
+ link: widget.link,
222
+ findWidget: findWidget,
223
+ deleteWidget: deleteWidget,
224
+ onDragStart: handleDragStart,
225
+ onDragEnd: handleDragEnd,
226
+ component: widget.component,
227
+ children: /*#__PURE__*/ jsxRuntime.jsx(WidgetComponent, {
228
+ component: widget.component,
229
+ columnWidth: widgetWidth
230
+ })
231
+ })
232
+ }),
233
+ !isLastInRow && canResize && rightWidgetId && /*#__PURE__*/ jsxRuntime.jsx(ResizeIndicator.WidgetResizeHandle, {
234
+ leftWidgetId: widget.uid,
235
+ rightWidgetId: rightWidgetId,
236
+ leftWidgetWidth: widgetWidth,
237
+ rightWidgetWidth: rightWidgetWidth,
238
+ onResize: handleWidgetResize,
239
+ saveLayout: saveLayout,
240
+ filteredWidgets: filteredWidgets
241
+ }, `resize-${widget.uid}`)
242
+ ]
243
+ }, widget.uid))
244
+ }),
245
+ isDraggingWidget && /*#__PURE__*/ jsxRuntime.jsx(GapDropZone.GapDropZoneManager, {
246
+ filteredWidgets: filteredWidgets,
247
+ columnWidths: columnWidths,
248
+ draggedWidgetId: draggedWidgetId,
249
+ moveWidget: moveWidget
250
+ })
251
+ ]
208
252
  })
209
253
  ]
210
254
  })
255
+ }),
256
+ /*#__PURE__*/ jsxRuntime.jsx(DragLayer.DragLayer, {
257
+ renderItem: ({ type, item })=>{
258
+ if (!DragLayer.isWidgetDragItem(item)) {
259
+ return null;
260
+ }
261
+ const widgetElement = widgetLayout.getWidgetElement(item.id);
262
+ const maxWidth = `${widgetElement?.clientWidth}px`;
263
+ return /*#__PURE__*/ jsxRuntime.jsx(DragPreviewWrapper, {
264
+ $maxWidth: maxWidth,
265
+ children: /*#__PURE__*/ jsxRuntime.jsx(WidgetRoot.WidgetRoot, {
266
+ uid: item.id,
267
+ title: item.title || {
268
+ id: `${item.id}`,
269
+ defaultMessage: item.id
270
+ },
271
+ icon: item.icon,
272
+ link: item.link,
273
+ children: /*#__PURE__*/ jsxRuntime.jsx(WidgetComponent, {
274
+ component: item.component,
275
+ columnWidth: 4
276
+ })
277
+ })
278
+ });
279
+ }
211
280
  })
212
281
  ]
213
282
  })
@@ -227,5 +296,5 @@ const WidgetRoot = ({ title, icon = icons.PuzzlePiece, children, link, uid })=>{
227
296
 
228
297
  exports.HomePage = HomePage;
229
298
  exports.HomePageCE = HomePageCE;
230
- exports.WidgetRoot = WidgetRoot;
299
+ exports.WidgetComponent = WidgetComponent;
231
300
  //# sourceMappingURL=HomePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"HomePage.js","sources":["../../../../../../admin/src/pages/Home/HomePage.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Flex, Grid, Typography, Main } from '@strapi/design-system';\nimport { PuzzlePiece } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { Link as ReactRouterLink } from 'react-router-dom';\n\nimport { GuidedTourHomepageOverview } from '../../components/GuidedTour/Overview';\nimport { Layouts } from '../../components/Layouts/Layout';\nimport { Page } from '../../components/PageHelpers';\nimport { Widget } from '../../components/WidgetHelpers';\nimport { useEnterprise } from '../../ee';\nimport { useAuth } from '../../features/Auth';\nimport { useStrapiApp } from '../../features/StrapiApp';\nimport { useTracking } from '../../features/Tracking';\n\nimport { FreeTrialEndedModal } from './components/FreeTrialEndedModal';\nimport { FreeTrialWelcomeModal } from './components/FreeTrialWelcomeModal';\n\nimport type { WidgetWithUID } from '../../core/apis/Widgets';\nimport type { WidgetType } from '@strapi/admin/strapi-admin';\n\n/* -------------------------------------------------------------------------------------------------\n * WidgetRoot\n * -----------------------------------------------------------------------------------------------*/\n\ninterface WidgetRootProps\n extends Pick<WidgetType, 'title' | 'icon' | 'permissions' | 'link' | 'uid'> {\n children: React.ReactNode;\n}\n\nexport const WidgetRoot = ({ title, icon = PuzzlePiece, children, link, uid }: WidgetRootProps) => {\n const { trackUsage } = useTracking();\n const { formatMessage } = useIntl();\n const id = React.useId();\n const Icon = icon;\n\n const handleClickOnLink = () => {\n trackUsage('didOpenHomeWidgetLink', { widgetUID: uid });\n };\n\n return (\n <Flex\n width=\"100%\"\n hasRadius\n direction=\"column\"\n alignItems=\"flex-start\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n shadow=\"tableShadow\"\n tag=\"section\"\n gap={4}\n padding={6}\n aria-labelledby={id}\n >\n <Flex direction=\"row\" gap={2} justifyContent=\"space-between\" width=\"100%\" tag=\"header\">\n <Flex gap={2}>\n <Icon fill=\"neutral500\" aria-hidden />\n <Typography textColor=\"neutral500\" variant=\"sigma\" tag=\"h2\" id={id}>\n {formatMessage(title)}\n </Typography>\n </Flex>\n {link && (\n <Typography\n tag={ReactRouterLink}\n variant=\"omega\"\n textColor=\"primary600\"\n style={{ textDecoration: 'none' }}\n textAlign=\"right\"\n to={link.href}\n onClick={handleClickOnLink}\n >\n {formatMessage(link.label)}\n </Typography>\n )}\n </Flex>\n <Box width=\"100%\" height=\"261px\" overflow=\"auto\" tag=\"main\">\n {children}\n </Box>\n </Flex>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * UnstableHomePageCe\n * -----------------------------------------------------------------------------------------------*/\n\nconst WidgetComponent = ({ component }: { component: () => Promise<React.ComponentType> }) => {\n const [loadedComponent, setLoadedComponent] = React.useState<React.ComponentType | null>(null);\n\n React.useEffect(() => {\n const loadComponent = async () => {\n const resolvedComponent = await component();\n\n setLoadedComponent(() => resolvedComponent);\n };\n\n loadComponent();\n }, [component]);\n\n const Component = loadedComponent;\n\n if (!Component) {\n return <Widget.Loading />;\n }\n\n return <Component />;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * HomePageCE\n * -----------------------------------------------------------------------------------------------*/\n\nconst HomePageCE = () => {\n const { formatMessage } = useIntl();\n const user = useAuth('HomePageCE', (state) => state.user);\n const displayName = user?.firstname ?? user?.username ?? user?.email;\n const getAllWidgets = useStrapiApp('UnstableHomepageCe', (state) => state.widgets.getAll);\n const checkUserHasPermissions = useAuth('WidgetRoot', (state) => state.checkUserHasPermissions);\n const [filteredWidgets, setFilteredWidgets] = React.useState<WidgetWithUID[]>([]);\n const [loading, setLoading] = React.useState(true);\n\n React.useEffect(() => {\n const checkWidgetsPermissions = async () => {\n const allWidgets = getAllWidgets();\n const authorizedWidgets = await Promise.all(\n allWidgets.map(async (widget) => {\n if (!widget.permissions || widget.permissions.length === 0) return true;\n const matchingPermissions = await checkUserHasPermissions(widget.permissions);\n return matchingPermissions.length >= widget.permissions.length;\n })\n );\n setFilteredWidgets(allWidgets.filter((_, i) => authorizedWidgets[i]));\n setLoading(false);\n };\n\n checkWidgetsPermissions();\n }, [checkUserHasPermissions, getAllWidgets]);\n\n return (\n <Layouts.Root>\n <Main>\n <Page.Title>\n {formatMessage({ id: 'HomePage.head.title', defaultMessage: 'Homepage' })}\n </Page.Title>\n <Layouts.Header\n title={formatMessage(\n { id: 'HomePage.header.title', defaultMessage: 'Hello {name}' },\n { name: displayName }\n )}\n subtitle={formatMessage({\n id: 'HomePage.header.subtitle',\n defaultMessage: 'Welcome to your administration panel',\n })}\n />\n <FreeTrialWelcomeModal />\n <FreeTrialEndedModal />\n <Layouts.Content>\n <Flex direction=\"column\" alignItems=\"stretch\" gap={8}>\n <GuidedTourHomepageOverview />\n {loading ? (\n <Box position=\"absolute\" top={0} left={0} right={0} bottom={0}>\n <Page.Loading />\n </Box>\n ) : (\n <Grid.Root gap={5}>\n {filteredWidgets.map((widget) => (\n <Grid.Item col={6} s={12} key={widget.uid}>\n <WidgetRoot\n title={widget.title}\n icon={widget.icon}\n link={widget.link}\n uid={widget.uid}\n >\n <WidgetComponent component={widget.component} />\n </WidgetRoot>\n </Grid.Item>\n ))}\n </Grid.Root>\n )}\n </Flex>\n </Layouts.Content>\n </Main>\n </Layouts.Root>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * HomePage\n * -----------------------------------------------------------------------------------------------*/\n\nconst HomePage = () => {\n const Page = useEnterprise(\n HomePageCE,\n // eslint-disable-next-line import/no-cycle\n async () => (await import('../../../../ee/admin/src/pages/HomePage')).HomePageEE\n );\n\n // block rendering until the EE component is fully loaded\n if (!Page) {\n return null;\n }\n\n return <Page />;\n};\n\nexport { HomePage, HomePageCE };\n"],"names":["WidgetRoot","title","icon","PuzzlePiece","children","link","uid","trackUsage","useTracking","formatMessage","useIntl","id","React","useId","Icon","handleClickOnLink","widgetUID","_jsxs","Flex","width","hasRadius","direction","alignItems","background","borderColor","shadow","tag","gap","padding","aria-labelledby","justifyContent","_jsx","fill","aria-hidden","Typography","textColor","variant","ReactRouterLink","style","textDecoration","textAlign","to","href","onClick","label","Box","height","overflow","WidgetComponent","component","loadedComponent","setLoadedComponent","useState","useEffect","loadComponent","resolvedComponent","Component","Widget","Loading","HomePageCE","user","useAuth","state","displayName","firstname","username","email","getAllWidgets","useStrapiApp","widgets","getAll","checkUserHasPermissions","filteredWidgets","setFilteredWidgets","loading","setLoading","checkWidgetsPermissions","allWidgets","authorizedWidgets","Promise","all","map","widget","permissions","length","matchingPermissions","filter","_","i","Layouts","Root","Main","Page","Title","defaultMessage","Header","name","subtitle","FreeTrialWelcomeModal","FreeTrialEndedModal","Content","GuidedTourHomepageOverview","position","top","left","right","bottom","Grid","Item","col","s","HomePage","useEnterprise","HomePageEE"],"mappings":"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"}
1
+ {"version":3,"file":"HomePage.js","sources":["../../../../../../admin/src/pages/Home/HomePage.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Button, Flex, Grid, Main } from '@strapi/design-system';\nimport { Plus } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { DragLayer, isWidgetDragItem } from '../../components/DragLayer';\nimport { GapDropZoneManager } from '../../components/GapDropZone';\nimport { GuidedTourHomepageOverview } from '../../components/GuidedTour/Overview';\nimport { Layouts } from '../../components/Layouts/Layout';\nimport { Page } from '../../components/PageHelpers';\nimport { WidgetResizeHandle } from '../../components/ResizeIndicator';\nimport { Widget } from '../../components/WidgetHelpers';\nimport { WidgetRoot } from '../../components/WidgetRoot';\nimport { useEnterprise } from '../../ee';\nimport { useAuth } from '../../features/Auth';\nimport { useStrapiApp } from '../../features/StrapiApp';\nimport { useWidgets } from '../../features/Widgets';\nimport { useGetHomepageLayoutQuery } from '../../services/homepage';\nimport { getWidgetElement, WIDGET_DATA_ATTRIBUTES } from '../../utils/widgetLayout';\nimport {\n applyHomepageLayout,\n createDefaultWidgetWidths,\n isLastWidgetInRow,\n canResizeBetweenWidgets,\n getWidgetWidth,\n} from '../../utils/widgetLayout';\n\nimport { AddWidgetModal } from './components/AddWidgetModal';\nimport { FreeTrialEndedModal } from './components/FreeTrialEndedModal';\nimport { FreeTrialWelcomeModal } from './components/FreeTrialWelcomeModal';\n\nimport type { WidgetWithUID } from '../../core/apis/Widgets';\n\n// Styled wrapper for the drag preview\nconst DragPreviewWrapper = styled.div<{ $maxWidth: string }>`\n max-width: ${(props) => props.$maxWidth};\n overflow: hidden;\n opacity: 0.9;\n border: 2px solid ${({ theme }) => theme.colors.primary500};\n border-radius: ${({ theme }) => theme.borderRadius};\n pointer-events: none;\n`;\n\n/* -------------------------------------------------------------------------------------------------\n * UnstableHomePageCe\n * -----------------------------------------------------------------------------------------------*/\n\nexport const WidgetComponent = ({\n component,\n columnWidth,\n}: {\n component: () => Promise<React.ComponentType>;\n columnWidth: number;\n}) => {\n const [loadedComponent, setLoadedComponent] = React.useState<React.ComponentType<{\n columnWidth?: number;\n }> | null>(null);\n\n React.useEffect(() => {\n const loadComponent = async () => {\n const resolvedComponent = await component();\n\n setLoadedComponent(() => resolvedComponent);\n };\n\n loadComponent();\n }, [component]);\n\n const Component = loadedComponent;\n\n if (!Component) {\n return <Widget.Loading />;\n }\n\n return <Component {...({ columnWidth } as Record<string, unknown>)} />;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * HomePageCE\n * -----------------------------------------------------------------------------------------------*/\n\nconst HomePageCE = () => {\n const { formatMessage } = useIntl();\n const user = useAuth('HomePageCE', (state) => state.user);\n const displayName = user?.firstname ?? user?.username ?? user?.email;\n const getAllWidgets = useStrapiApp('UnstableHomepageCe', (state) => state.widgets.getAll);\n const checkUserHasPermissions = useAuth('WidgetRoot', (state) => state.checkUserHasPermissions);\n const { data: homepageLayout, isLoading: _isLoadingLayout } = useGetHomepageLayoutQuery();\n const [filteredWidgets, setFilteredWidgets] = React.useState<WidgetWithUID[]>([]);\n const [allAvailableWidgets, setAllAvailableWidgets] = React.useState<WidgetWithUID[]>([]);\n const [loading, setLoading] = React.useState(true);\n const [isAddWidgetModalOpen, setIsAddWidgetModalOpen] = React.useState(false);\n\n // Use custom hook for widget management\n const {\n findWidget,\n deleteWidget,\n addWidget,\n moveWidget,\n columnWidths,\n setColumnWidths,\n handleWidgetResize,\n saveLayout,\n isDraggingWidget,\n draggedWidgetId,\n handleDragStart,\n handleDragEnd,\n } = useWidgets({\n filteredWidgets,\n setFilteredWidgets,\n });\n\n React.useEffect(() => {\n const checkWidgetsPermissions = async () => {\n const allWidgets = getAllWidgets();\n const authorizedWidgets = await Promise.all(\n allWidgets.map(async (widget) => {\n if (!widget.permissions || widget.permissions.length === 0) return true;\n const matchingPermissions = await checkUserHasPermissions(widget.permissions);\n return matchingPermissions.length >= widget.permissions.length;\n })\n );\n const authorizedWidgetsList = allWidgets.filter((_, i) => authorizedWidgets[i]);\n\n setAllAvailableWidgets(authorizedWidgetsList);\n setLoading(false);\n };\n\n checkWidgetsPermissions();\n }, [checkUserHasPermissions, getAllWidgets]);\n\n React.useEffect(() => {\n if (allAvailableWidgets.length === 0) return;\n\n // If user has customized the homepage layout, apply it\n if (homepageLayout && homepageLayout.widgets) {\n const { filteredWidgets, widths: homepageWidths } = applyHomepageLayout(\n allAvailableWidgets,\n homepageLayout\n );\n\n setFilteredWidgets(filteredWidgets);\n setColumnWidths(homepageWidths);\n } else {\n // Set default layout when no custom layout exists\n setFilteredWidgets(allAvailableWidgets);\n setColumnWidths(createDefaultWidgetWidths(allAvailableWidgets));\n }\n }, [homepageLayout, allAvailableWidgets, setColumnWidths]);\n\n const widgetLayout = React.useMemo(() => {\n return filteredWidgets.map((widget, index) => {\n const rightWidgetId = filteredWidgets[index + 1]?.uid;\n const widgetWidth = getWidgetWidth(columnWidths, widget.uid);\n const rightWidgetWidth = getWidgetWidth(columnWidths, rightWidgetId);\n\n return {\n widget,\n index,\n isLastInRow: isLastWidgetInRow(index, filteredWidgets, columnWidths),\n rightWidgetId,\n widgetWidth,\n rightWidgetWidth,\n canResize:\n rightWidgetId &&\n canResizeBetweenWidgets(widget.uid, rightWidgetId, columnWidths, filteredWidgets),\n };\n });\n }, [filteredWidgets, columnWidths]);\n\n return (\n <Layouts.Root>\n <Main>\n <Page.Title>\n {formatMessage({ id: 'HomePage.head.title', defaultMessage: 'Homepage' })}\n </Page.Title>\n <Layouts.Header\n title={formatMessage(\n { id: 'HomePage.header.title', defaultMessage: 'Hello {name}' },\n { name: displayName }\n )}\n subtitle={formatMessage({\n id: 'HomePage.header.subtitle',\n defaultMessage: 'Welcome to your administration panel',\n })}\n primaryAction={\n <Button\n variant=\"tertiary\"\n size=\"S\"\n startIcon={<Plus />}\n onClick={() => setIsAddWidgetModalOpen(true)}\n >\n {formatMessage({\n id: 'HomePage.addWidget.button',\n defaultMessage: 'Add Widget',\n })}\n </Button>\n }\n />\n <FreeTrialWelcomeModal />\n <FreeTrialEndedModal />\n <AddWidgetModal\n isOpen={isAddWidgetModalOpen}\n onClose={() => setIsAddWidgetModalOpen(false)}\n onAddWidget={addWidget}\n currentWidgets={filteredWidgets}\n availableWidgets={allAvailableWidgets}\n />\n <Layouts.Content>\n <Flex direction=\"column\" alignItems=\"stretch\" gap={8} paddingBottom={10}>\n <GuidedTourHomepageOverview />\n {loading ? (\n <Box position=\"absolute\" top={0} left={0} right={0} bottom={0}>\n <Page.Loading />\n </Box>\n ) : (\n <Box position=\"relative\" {...{ [WIDGET_DATA_ATTRIBUTES.GRID_CONTAINER]: true }}>\n <Grid.Root gap={5}>\n {widgetLayout.map(\n ({\n widget,\n isLastInRow,\n rightWidgetId,\n widgetWidth,\n rightWidgetWidth,\n canResize,\n }) => (\n <React.Fragment key={widget.uid}>\n <Grid.Item col={widgetWidth} s={12}>\n <WidgetRoot\n uid={widget.uid}\n title={widget.title}\n icon={widget.icon}\n link={widget.link}\n findWidget={findWidget}\n deleteWidget={deleteWidget}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n component={widget.component}\n >\n <WidgetComponent\n component={widget.component}\n columnWidth={widgetWidth}\n />\n </WidgetRoot>\n </Grid.Item>\n\n {!isLastInRow && canResize && rightWidgetId && (\n <WidgetResizeHandle\n key={`resize-${widget.uid}`}\n leftWidgetId={widget.uid}\n rightWidgetId={rightWidgetId}\n leftWidgetWidth={widgetWidth}\n rightWidgetWidth={rightWidgetWidth}\n onResize={handleWidgetResize}\n saveLayout={saveLayout}\n filteredWidgets={filteredWidgets}\n />\n )}\n </React.Fragment>\n )\n )}\n </Grid.Root>\n\n {isDraggingWidget && (\n <GapDropZoneManager\n filteredWidgets={filteredWidgets}\n columnWidths={columnWidths}\n draggedWidgetId={draggedWidgetId}\n moveWidget={moveWidget}\n />\n )}\n </Box>\n )}\n </Flex>\n </Layouts.Content>\n\n {/* Add the DragLayer to handle custom drag previews */}\n <DragLayer\n renderItem={({ type, item }) => {\n if (!isWidgetDragItem(item)) {\n return null;\n }\n\n const widgetElement = getWidgetElement(item.id);\n const maxWidth = `${widgetElement?.clientWidth}px`;\n\n return (\n <DragPreviewWrapper $maxWidth={maxWidth}>\n <WidgetRoot\n uid={item.id as WidgetWithUID['uid']}\n title={item.title || { id: `${item.id}`, defaultMessage: item.id }}\n icon={item.icon}\n link={item.link}\n >\n <WidgetComponent component={item.component} columnWidth={4} />\n </WidgetRoot>\n </DragPreviewWrapper>\n );\n }}\n />\n </Main>\n </Layouts.Root>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * HomePage\n * -----------------------------------------------------------------------------------------------*/\n\nconst HomePage = () => {\n const Page = useEnterprise(\n HomePageCE,\n // eslint-disable-next-line import/no-cycle\n async () => (await import('../../../../ee/admin/src/pages/HomePage')).HomePageEE\n );\n\n // block rendering until the EE component is fully loaded\n if (!Page) {\n return null;\n }\n\n return <Page />;\n};\n\nexport { HomePage, HomePageCE };\n"],"names":["DragPreviewWrapper","styled","div","props","$maxWidth","theme","colors","primary500","borderRadius","WidgetComponent","component","columnWidth","loadedComponent","setLoadedComponent","React","useState","useEffect","loadComponent","resolvedComponent","Component","_jsx","Widget","Loading","HomePageCE","formatMessage","useIntl","user","useAuth","state","displayName","firstname","username","email","getAllWidgets","useStrapiApp","widgets","getAll","checkUserHasPermissions","data","homepageLayout","isLoading","_isLoadingLayout","useGetHomepageLayoutQuery","filteredWidgets","setFilteredWidgets","allAvailableWidgets","setAllAvailableWidgets","loading","setLoading","isAddWidgetModalOpen","setIsAddWidgetModalOpen","findWidget","deleteWidget","addWidget","moveWidget","columnWidths","setColumnWidths","handleWidgetResize","saveLayout","isDraggingWidget","draggedWidgetId","handleDragStart","handleDragEnd","useWidgets","checkWidgetsPermissions","allWidgets","authorizedWidgets","Promise","all","map","widget","permissions","length","matchingPermissions","authorizedWidgetsList","filter","_","i","widths","homepageWidths","applyHomepageLayout","createDefaultWidgetWidths","widgetLayout","useMemo","index","rightWidgetId","uid","widgetWidth","getWidgetWidth","rightWidgetWidth","isLastInRow","isLastWidgetInRow","canResize","canResizeBetweenWidgets","Layouts","Root","_jsxs","Main","Page","Title","id","defaultMessage","Header","title","name","subtitle","primaryAction","Button","variant","size","startIcon","Plus","onClick","FreeTrialWelcomeModal","FreeTrialEndedModal","AddWidgetModal","isOpen","onClose","onAddWidget","currentWidgets","availableWidgets","Content","Flex","direction","alignItems","gap","paddingBottom","GuidedTourHomepageOverview","Box","position","top","left","right","bottom","WIDGET_DATA_ATTRIBUTES","GRID_CONTAINER","Grid","Fragment","Item","col","s","WidgetRoot","icon","link","onDragStart","onDragEnd","WidgetResizeHandle","leftWidgetId","leftWidgetWidth","onResize","GapDropZoneManager","DragLayer","renderItem","type","item","isWidgetDragItem","widgetElement","getWidgetElement","maxWidth","clientWidth","HomePage","useEnterprise","HomePageEE"],"mappings":"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"}