diff --git a/.changeset/cold-keys-press.md b/.changeset/cold-keys-press.md new file mode 100644 index 0000000000..74376555e9 --- /dev/null +++ b/.changeset/cold-keys-press.md @@ -0,0 +1,12 @@ +--- +"@medusajs/admin-vite-plugin": patch +"@medusajs/admin-bundler": patch +"@medusajs/test-utils": patch +"@medusajs/dashboard": patch +"@medusajs/framework": patch +"@medusajs/types": patch +"@medusajs/utils": patch +"@medusajs/medusa": patch +--- + +fix(medusa,utils,test-utils,types,framework,dashboard,admin-vite-plugin,admib-bundler): Fix broken plugin dependencies in development server diff --git a/packages/admin/admin-bundler/package.json b/packages/admin/admin-bundler/package.json index 547c0be2ba..40f25c6bd6 100644 --- a/packages/admin/admin-bundler/package.json +++ b/packages/admin/admin-bundler/package.json @@ -4,7 +4,7 @@ "description": "Bundler for the Medusa admin dashboard.", "author": "Kasper Kristensen ", "scripts": { - "build": "tsup && copyfiles -f ./src/index.html ./src/entry.tsx ./src/index.css ./dist" + "build": "tsup" }, "main": "./dist/index.js", "types": "./dist/index.d.ts", @@ -20,7 +20,6 @@ "devDependencies": { "@medusajs/types": "2.6.1", "@types/compression": "^1.7.5", - "copyfiles": "^2.4.1", "express": "^4.21.0", "tsup": "^8.0.1", "typescript": "^5.3.3" @@ -29,19 +28,16 @@ "@medusajs/admin-shared": "2.6.1", "@medusajs/admin-vite-plugin": "2.6.1", "@medusajs/dashboard": "2.6.1", - "@rollup/plugin-node-resolve": "^16.0.0", "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.16", "compression": "^1.7.4", "express": "^4.21.0", "get-port": "^5.1.1", "glob": "^10.3.10", + "outdent": "^0.8.0", "postcss": "^8.4.32", "tailwindcss": "^3.3.6", "vite": "^5.4.14" }, - "peerDependencies": { - "react-dom": "^18.0.0" - }, "packageManager": "yarn@3.2.1" } diff --git a/packages/admin/admin-bundler/src/lib/build.ts b/packages/admin/admin-bundler/src/commands/build.ts similarity index 88% rename from packages/admin/admin-bundler/src/lib/build.ts rename to packages/admin/admin-bundler/src/commands/build.ts index 86f902f74b..9abb8e37b1 100644 --- a/packages/admin/admin-bundler/src/lib/build.ts +++ b/packages/admin/admin-bundler/src/commands/build.ts @@ -1,6 +1,6 @@ import type { InlineConfig } from "vite" import { BundlerOptions } from "../types" -import { getViteConfig } from "./config" +import { getViteConfig } from "../utils/config" export async function build(options: BundlerOptions) { const vite = await import("vite") diff --git a/packages/admin/admin-bundler/src/lib/develop.ts b/packages/admin/admin-bundler/src/commands/develop.ts similarity index 97% rename from packages/admin/admin-bundler/src/lib/develop.ts rename to packages/admin/admin-bundler/src/commands/develop.ts index f64d1b6e3e..099899e4dd 100644 --- a/packages/admin/admin-bundler/src/lib/develop.ts +++ b/packages/admin/admin-bundler/src/commands/develop.ts @@ -4,7 +4,7 @@ import path from "path" import type { InlineConfig, ViteDevServer } from "vite" import { BundlerOptions } from "../types" -import { getViteConfig } from "./config" +import { getViteConfig } from "../utils/config" const router = express.Router() diff --git a/packages/admin/admin-bundler/src/commands/plugin.ts b/packages/admin/admin-bundler/src/commands/plugin.ts new file mode 100644 index 0000000000..c9e35afe53 --- /dev/null +++ b/packages/admin/admin-bundler/src/commands/plugin.ts @@ -0,0 +1,112 @@ +import { readFileSync } from "fs" +import { builtinModules } from "node:module" +import path from "path" +import type { UserConfig } from "vite" +import { clearPluginBuild } from "../plugins/clear-plugin-build" + +interface PluginOptions { + root: string + outDir: string +} + +export async function plugin(options: PluginOptions) { + const vite = await import("vite") + const react = (await import("@vitejs/plugin-react")).default + const medusa = (await import("@medusajs/admin-vite-plugin")).default + + const pkg = JSON.parse( + readFileSync(path.resolve(options.root, "package.json"), "utf-8") + ) + const external = new Set([ + ...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.peerDependencies || {}), + ...Object.keys(pkg.devDependencies || {}), + "react", + "react/jsx-runtime", + "react-router-dom", + "@medusajs/js-sdk", + "@medusajs/admin-sdk", + "@tanstack/react-query", + ]) + + const outDir = path.resolve(options.root, options.outDir, "src/admin") + const entryPoint = path.resolve( + options.root, + "src/admin/__admin-extensions__.js" + ) + + /** + * We need to ensure that the NODE_ENV is set to production, + * otherwise Vite will build the dev version of React. + */ + const originalNodeEnv = process.env.NODE_ENV + process.env.NODE_ENV = "production" + + const pluginConfig: UserConfig = { + build: { + lib: { + entry: entryPoint, + formats: ["es", "cjs"], + fileName: "index", + }, + emptyOutDir: false, + minify: false, + outDir, + rollupOptions: { + external: (id, importer) => { + // If there's no importer, it's a direct dependency + // Keep the existing external behavior + if (!importer) { + const idParts = id.split("/") + const name = idParts[0]?.startsWith("@") + ? `${idParts[0]}/${idParts[1]}` + : idParts[0] + + const builtinModulesWithNodePrefix = [ + ...builtinModules, + ...builtinModules.map((modName) => `node:${modName}`), + ] + + return Boolean( + (name && external.has(name)) || + (name && builtinModulesWithNodePrefix.includes(name)) + ) + } + + // For transient dependencies (those with importers), + // bundle them if they're not in our external set + const idParts = id.split("/") + const name = idParts[0]?.startsWith("@") + ? `${idParts[0]}/${idParts[1]}` + : idParts[0] + + return Boolean(name && external.has(name)) + }, + output: { + preserveModules: false, + interop: "auto", + chunkFileNames: () => { + return `_chunks/[name]-[hash]` + }, + }, + }, + }, + plugins: [ + react(), + medusa({ + pluginMode: true, + sources: [path.resolve(options.root, "src/admin")], + }), + clearPluginBuild({ outDir }), + ], + logLevel: "silent", + clearScreen: false, + } + + await vite.build(pluginConfig) + + /** + * Restore the original NODE_ENV + */ + process.env.NODE_ENV = originalNodeEnv +} diff --git a/packages/admin/admin-bundler/src/lib/serve.ts b/packages/admin/admin-bundler/src/commands/serve.ts similarity index 100% rename from packages/admin/admin-bundler/src/lib/serve.ts rename to packages/admin/admin-bundler/src/commands/serve.ts diff --git a/packages/admin/admin-bundler/src/entry.tsx b/packages/admin/admin-bundler/src/entry.tsx deleted file mode 100644 index 996d8d8030..0000000000 --- a/packages/admin/admin-bundler/src/entry.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import App from "@medusajs/dashboard"; -import React from "react"; -import ReactDOM from "react-dom/client"; -import "./index.css"; - -ReactDOM.createRoot(document.getElementById("medusa")!).render( - - - -) - - -if (import.meta.hot) { - import.meta.hot.accept() -} diff --git a/packages/admin/admin-bundler/src/index.css b/packages/admin/admin-bundler/src/index.css deleted file mode 100644 index c9b2a6f230..0000000000 --- a/packages/admin/admin-bundler/src/index.css +++ /dev/null @@ -1,5 +0,0 @@ -@import "@medusajs/dashboard/css"; - -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/packages/admin/admin-bundler/src/index.html b/packages/admin/admin-bundler/src/index.html deleted file mode 100644 index d01be5fa97..0000000000 --- a/packages/admin/admin-bundler/src/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - -
- - - diff --git a/packages/admin/admin-bundler/src/index.ts b/packages/admin/admin-bundler/src/index.ts index d642941a6e..c3570ff546 100644 --- a/packages/admin/admin-bundler/src/index.ts +++ b/packages/admin/admin-bundler/src/index.ts @@ -1,6 +1,6 @@ -export { build } from "./lib/build" -export { develop } from "./lib/develop" -export { plugin } from "./lib/plugin" -export { serve } from "./lib/serve" +export { build } from "./commands/build" +export { develop } from "./commands/develop" +export { plugin } from "./commands/plugin" +export { serve } from "./commands/serve" export * from "./types" diff --git a/packages/admin/admin-bundler/src/lib/plugin.ts b/packages/admin/admin-bundler/src/lib/plugin.ts deleted file mode 100644 index f589646dad..0000000000 --- a/packages/admin/admin-bundler/src/lib/plugin.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { readFileSync } from "fs" -import { rm } from "fs/promises" -import { glob } from "glob" -import path from "path" -import type { UserConfig } from "vite" - -interface PluginOptions { - root: string - outDir: string -} - -export async function plugin(options: PluginOptions) { - const vite = await import("vite") - const react = (await import("@vitejs/plugin-react")).default - const { nodeResolve } = await import("@rollup/plugin-node-resolve") - const entries = await glob(`${options.root}/src/admin/**/*.{ts,tsx,js,jsx}`) - - /** - * If there is no entry point, we can skip the build - */ - if (entries.length === 0) { - return - } - - const entryPoints = entries.reduce((acc, entry) => { - const outPath = entry - .replace(/^src\//, "") - .replace(/\.(ts|tsx|js|jsx)$/, "") - - acc[outPath] = path.resolve(options.root, entry) - return acc - }, {} as Record) - - const pkg = JSON.parse( - readFileSync(path.resolve(options.root, "package.json"), "utf-8") - ) - const external = new Set([ - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}), - ...Object.keys(pkg.devDependencies || {}), - "react", - "react-dom", - "react/jsx-runtime", - "react-router-dom", - "@medusajs/admin-sdk", - "@tanstack/react-query", - ]) - - /** - * We need to ensure that the NODE_ENV is set to production, - * otherwise Vite will build the dev version of React. - */ - const originalNodeEnv = process.env.NODE_ENV - process.env.NODE_ENV = "production" - - const pluginConfig: UserConfig = { - build: { - lib: { - entry: entryPoints, - formats: ["es"], - }, - emptyOutDir: false, - minify: false, - outDir: path.resolve(options.root, options.outDir), - rollupOptions: { - plugins: [nodeResolve() as any], - external: [...external, /node_modules/], - output: { - globals: { - react: "React", - "react-dom": "React-dom", - "react/jsx-runtime": "react/jsx-runtime", - }, - preserveModules: true, - entryFileNames: (chunkInfo) => { - return `${chunkInfo.name.replace(`${options.root}/`, "")}.js` - }, - }, - }, - }, - plugins: [ - react(), - { - name: "clear-admin-plugin", - buildStart: async () => { - const adminDir = path.join(options.root, options.outDir, "admin") - try { - await rm(adminDir, { recursive: true, force: true }) - } catch (e) { - // Directory might not exist, ignore - } - }, - }, - ], - logLevel: "silent", - clearScreen: false, - } - - await vite.build(pluginConfig) - - /** - * Restore the original NODE_ENV - */ - process.env.NODE_ENV = originalNodeEnv -} diff --git a/packages/admin/admin-bundler/src/plugins/clear-plugin-build.ts b/packages/admin/admin-bundler/src/plugins/clear-plugin-build.ts new file mode 100644 index 0000000000..9e608498ff --- /dev/null +++ b/packages/admin/admin-bundler/src/plugins/clear-plugin-build.ts @@ -0,0 +1,19 @@ +import { rm } from "node:fs/promises" +import path from "node:path" +import type { Plugin } from "vite" + +interface ClearPluginBuildOptions { + outDir: string +} + +export const clearPluginBuild = (options: ClearPluginBuildOptions): Plugin => ({ + name: "medusa:clear-plugin-build", + buildStart: async () => { + const adminDir = path.join(options.outDir, "admin") + try { + await rm(adminDir, { recursive: true, force: true }) + } catch (e) { + // Directory might not exist, ignore + } + }, +}) diff --git a/packages/admin/admin-bundler/src/plugins/inject-tailwindcss.ts b/packages/admin/admin-bundler/src/plugins/inject-tailwindcss.ts new file mode 100644 index 0000000000..f53c6e5716 --- /dev/null +++ b/packages/admin/admin-bundler/src/plugins/inject-tailwindcss.ts @@ -0,0 +1,96 @@ +import path from "node:path" +import type { Config } from "tailwindcss" +import type { Plugin } from "vite" + +interface InjectTailwindCSSOptions { + entry: string + sources?: string[] + plugins?: string[] +} + +export const injectTailwindCSS = ( + options: InjectTailwindCSSOptions +): Plugin => { + return { + name: "medusa:inject-tailwindcss", + config: () => ({ + css: { + postcss: { + plugins: [ + require("tailwindcss")({ + config: createTailwindConfig( + options.entry, + options.sources, + options.plugins + ), + }), + ], + }, + }, + }), + } +} + +function createTailwindConfig( + entry: string, + sources: string[] = [], + plugins: string[] = [] +) { + const root = path.join(entry, "**/*.{js,ts,jsx,tsx}") + const html = path.join(entry, "index.html") + + let dashboard = "" + + try { + dashboard = path.join( + path.dirname(require.resolve("@medusajs/dashboard")), + "**/*.{js,ts,jsx,tsx}" + ) + } catch (_e) { + // ignore + } + + let ui: string = "" + + try { + ui = path.join( + path.dirname(require.resolve("@medusajs/ui")), + "**/*.{js,ts,jsx,tsx}" + ) + } catch (_e) { + // ignore + } + + const sourceExtensions = sources.map((s) => + path.join(s, "**/*.{js,ts,jsx,tsx}") + ) + const pluginExtensions: string[] = [] + + for (const plugin of plugins) { + try { + const pluginPath = path.join( + path.dirname(require.resolve(plugin)), + "**/*.{js,ts,jsx,tsx}" + ) + + pluginExtensions.push(pluginPath) + } catch (_e) { + // ignore + } + } + + const config: Config = { + presets: [require("@medusajs/ui-preset")], + content: [ + html, + root, + dashboard, + ui, + ...sourceExtensions, + ...pluginExtensions, + ], + darkMode: "class", + } + + return config +} diff --git a/packages/admin/admin-bundler/src/plugins/write-static-files.ts b/packages/admin/admin-bundler/src/plugins/write-static-files.ts new file mode 100644 index 0000000000..18910d7bfe --- /dev/null +++ b/packages/admin/admin-bundler/src/plugins/write-static-files.ts @@ -0,0 +1,17 @@ +import type { Plugin } from "vite" +import { writeStaticFiles as writeStaticFilesUtils } from "../utils/write-static-files" + +interface WriteStaticFilesPluginOptions { + plugins?: string[] +} + +export const writeStaticFiles = ( + options: WriteStaticFilesPluginOptions +): Plugin => { + return { + name: "medusa:write-static-files", + buildStart: async (ctx) => { + await writeStaticFilesUtils(options.plugins) + }, + } +} diff --git a/packages/admin/admin-bundler/src/types.ts b/packages/admin/admin-bundler/src/types.ts index 491307037e..a1f62e3416 100644 --- a/packages/admin/admin-bundler/src/types.ts +++ b/packages/admin/admin-bundler/src/types.ts @@ -4,4 +4,5 @@ export type BundlerOptions = Required> & Pick & { outDir: string sources?: string[] + plugins?: string[] } diff --git a/packages/admin/admin-bundler/src/lib/config.ts b/packages/admin/admin-bundler/src/utils/config.ts similarity index 61% rename from packages/admin/admin-bundler/src/lib/config.ts rename to packages/admin/admin-bundler/src/utils/config.ts index 90128f92c2..fce808368c 100644 --- a/packages/admin/admin-bundler/src/lib/config.ts +++ b/packages/admin/admin-bundler/src/utils/config.ts @@ -1,7 +1,8 @@ import { VIRTUAL_MODULES } from "@medusajs/admin-shared" import path from "path" -import { Config } from "tailwindcss" import type { InlineConfig } from "vite" +import { injectTailwindCSS } from "../plugins/inject-tailwindcss" +import { writeStaticFiles } from "../plugins/write-static-files" import { BundlerOptions } from "../types" export async function getViteConfig( @@ -14,7 +15,7 @@ export async function getViteConfig( const getPort = await import("get-port") const hmrPort = await getPort.default() - const root = path.resolve(__dirname, "./") + const root = path.resolve(process.cwd(), ".medusa/client") const backendUrl = options.backendUrl ?? "" const storefrontUrl = options.storefrontUrl ?? "" @@ -52,16 +53,15 @@ export async function getViteConfig( port: hmrPort, }, }, - css: { - postcss: { - plugins: [ - require("tailwindcss")({ - config: createTailwindConfig(root, options.sources), - }), - ], - }, - }, plugins: [ + writeStaticFiles({ + plugins: options.plugins, + }), + injectTailwindCSS({ + entry: root, + sources: options.sources, + plugins: options.plugins, + }), react(), medusa({ sources: options.sources, @@ -76,40 +76,3 @@ export async function getViteConfig( return baseConfig } - -function createTailwindConfig(entry: string, sources: string[] = []) { - const root = path.join(entry, "**/*.{js,ts,jsx,tsx}") - const html = path.join(entry, "index.html") - - let dashboard = "" - - try { - dashboard = path.join( - path.dirname(require.resolve("@medusajs/dashboard")), - "**/*.{js,ts,jsx,tsx}" - ) - } catch (_e) { - // ignore - } - - let ui: string = "" - - try { - ui = path.join( - path.dirname(require.resolve("@medusajs/ui")), - "**/*.{js,ts,jsx,tsx}" - ) - } catch (_e) { - // ignore - } - - const extensions = sources.map((s) => path.join(s, "**/*.{js,ts,jsx,tsx}")) - - const config: Config = { - presets: [require("@medusajs/ui-preset")], - content: [html, root, dashboard, ui, ...extensions], - darkMode: "class", - } - - return config -} diff --git a/packages/admin/admin-bundler/src/utils/write-static-files.ts b/packages/admin/admin-bundler/src/utils/write-static-files.ts new file mode 100644 index 0000000000..93318fda55 --- /dev/null +++ b/packages/admin/admin-bundler/src/utils/write-static-files.ts @@ -0,0 +1,94 @@ +import { mkdir, writeFile } from "node:fs/promises" +import { join } from "node:path" +import outdent from "outdent" + +export async function writeStaticFiles(plugins?: string[]) { + const outDir = join(process.cwd(), ".medusa/client") + + await mkdir(outDir, { recursive: true }) + + const promises = [ + writeCSSFile(outDir), + writeEntryFile(outDir, plugins), + writeHTMLFile(outDir), + ] + + await Promise.all(promises) +} + +async function writeCSSFile(outDir: string) { + const css = outdent` + @import "@medusajs/dashboard/css"; + + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + await writeFile(join(outDir, "index.css"), css) +} + +function getPluginName(index: number) { + return `plugin${index}` +} + +async function writeEntryFile(outDir: string, plugins?: string[]) { + const entry = outdent` + import App from "@medusajs/dashboard"; + import React from "react"; + import ReactDOM from "react-dom/client"; + import "./index.css"; + + ${plugins + ?.map((plugin, idx) => `import ${getPluginName(idx)} from "${plugin}"`) + .join("\n")} + + let root = null + + if (!root) { + root = ReactDOM.createRoot(document.getElementById("medusa")) + } + + + root.render( + + getPluginName(idx)) + .join(", ")}]} /> + + ) + + + if (import.meta.hot) { + import.meta.hot.accept() + } + ` + + await writeFile(join(outDir, "entry.jsx"), entry) +} + +async function writeHTMLFile(outDir: string) { + const html = outdent` + + + + + + + + + +
+ + + + ` + + await writeFile(join(outDir, "index.html"), html) +} diff --git a/packages/admin/admin-vite-plugin/src/plugin.ts b/packages/admin/admin-vite-plugin/src/plugin.ts index 5cc2233ae0..c19d828e98 100644 --- a/packages/admin/admin-vite-plugin/src/plugin.ts +++ b/packages/admin/admin-vite-plugin/src/plugin.ts @@ -1,5 +1,6 @@ import { SourceMap } from "magic-string" -import path from "path" +import { rm, writeFile } from "node:fs/promises" +import path from "node:path" import type * as Vite from "vite" import { generateCustomFieldHashes } from "./custom-fields" import { generateRouteHashes } from "./routes" @@ -22,10 +23,17 @@ import { } from "./vmod" import { generateWidgetHash } from "./widgets" +enum Mode { + PLUGIN = "plugin", + APPLICATION = "application", +} + export const medusaVitePlugin: MedusaVitePlugin = (options) => { const hashMap = new Map() const _sources = new Set(options?.sources ?? []) + const mode = options?.pluginMode ? Mode.PLUGIN : Mode.APPLICATION + let watcher: Vite.FSWatcher | undefined function isFileInSources(file: string): boolean { @@ -66,9 +74,73 @@ export const medusaVitePlugin: MedusaVitePlugin = (options) => { } } + // Function to generate the index.js file + async function generatePluginEntryModule( + sources: Set + ): Promise { + // Generate all the module content + const widgetModule = await generateVirtualWidgetModule(sources, true) + const routeModule = await generateVirtualRouteModule(sources, true) + const menuItemModule = await generateVirtualMenuItemModule(sources, true) + const formModule = await generateVirtualFormModule(sources, true) + const displayModule = await generateVirtualDisplayModule(sources, true) + + // Create the index.js content that re-exports everything + return ` + // Auto-generated index file for Medusa Admin UI extensions + ${widgetModule.code} + ${routeModule.code} + ${menuItemModule.code} + ${formModule.code} + ${displayModule.code} + + const plugin = { + widgetModule, + routeModule, + menuItemModule, + formModule, + displayModule + } + + export default plugin + ` + } + + const pluginEntryFile = path.resolve( + process.cwd(), + "src/admin/__admin-extensions__.js" + ) + return { name: "@medusajs/admin-vite-plugin", enforce: "pre", + async buildStart() { + switch (mode) { + case Mode.PLUGIN: { + const code = await generatePluginEntryModule(_sources) + await writeFile(pluginEntryFile, code, "utf-8") + break + } + case Mode.APPLICATION: { + break + } + } + }, + async buildEnd() { + switch (mode) { + case Mode.PLUGIN: { + try { + await rm(pluginEntryFile, { force: true }) + } catch (error) { + // Ignore the error if the file doesn't exist + } + break + } + case Mode.APPLICATION: { + break + } + } + }, configureServer(server) { watcher = server.watcher watcher?.add(Array.from(_sources)) diff --git a/packages/admin/admin-vite-plugin/src/types.ts b/packages/admin/admin-vite-plugin/src/types.ts index a14af187e9..3a8e0c8527 100644 --- a/packages/admin/admin-vite-plugin/src/types.ts +++ b/packages/admin/admin-vite-plugin/src/types.ts @@ -56,6 +56,7 @@ export type LoadModuleOptions = export interface MedusaVitePluginOptions { sources?: string[] + pluginMode?: boolean } export type MedusaVitePlugin = (config?: MedusaVitePluginOptions) => Vite.Plugin diff --git a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-display-module.ts b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-display-module.ts index ec0c476a55..e8118b4af7 100644 --- a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-display-module.ts +++ b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-display-module.ts @@ -2,14 +2,19 @@ import { outdent } from "outdent" import { generateCustomFieldDisplays } from "../custom-fields" import { generateModule } from "../utils" -export async function generateVirtualDisplayModule(sources: Set) { +export async function generateVirtualDisplayModule( + sources: Set, + pluginMode = false +) { const displays = await generateCustomFieldDisplays(sources) const code = outdent` ${displays.imports.join("\n")} - export default { - ${displays.code} + ${ + pluginMode + ? `const displayModule = { ${displays.code} }` + : `export default { ${displays.code} }` } ` diff --git a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-form-module.ts b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-form-module.ts index e2ce152616..24f2248ded 100644 --- a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-form-module.ts +++ b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-form-module.ts @@ -1,29 +1,24 @@ import outdent from "outdent" import { generateCustomFieldForms } from "../custom-fields" -import { generateMenuItems } from "../routes" import { generateModule } from "../utils" -import { generateWidgets } from "../widgets" -export async function generateVirtualFormModule(sources: Set) { - const menuItems = await generateMenuItems(sources) - const widgets = await generateWidgets(sources) +export async function generateVirtualFormModule( + sources: Set, + pluginMode = false +) { const customFields = await generateCustomFieldForms(sources) - const imports = [ - ...menuItems.imports, - ...widgets.imports, - ...customFields.imports, - ] + const imports = [...customFields.imports] const code = outdent` ${imports.join("\n")} - export default { - ${menuItems.code}, - ${widgets.code}, - ${customFields.code}, - } - ` + ${ + pluginMode + ? `const formModule = { ${customFields.code} }` + : `export default { ${customFields.code} }` + } + ` return generateModule(code) } diff --git a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-link-module.ts b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-link-module.ts index ef37c4606e..c5a574b6ff 100644 --- a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-link-module.ts +++ b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-link-module.ts @@ -2,14 +2,19 @@ import { outdent } from "outdent" import { generateCustomFieldLinks } from "../custom-fields" import { generateModule } from "../utils" -export async function generateVirtualLinkModule(sources: Set) { +export async function generateVirtualLinkModule( + sources: Set, + pluginMode = false +) { const links = await generateCustomFieldLinks(sources) const code = outdent` ${links.imports.join("\n")} - export default { - ${links.code} + ${ + pluginMode + ? `const linkModule = { ${links.code} }` + : `export default { ${links.code} }` } ` diff --git a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-menu-item-module.ts b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-menu-item-module.ts index b76e0acc9b..2477cb857c 100644 --- a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-menu-item-module.ts +++ b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-menu-item-module.ts @@ -3,16 +3,21 @@ import outdent from "outdent" import { generateMenuItems } from "../routes" import { generateModule } from "../utils" -export async function generateVirtualMenuItemModule(sources: Set) { +export async function generateVirtualMenuItemModule( + sources: Set, + pluginMode = false +) { const menuItems = await generateMenuItems(sources) const code = outdent` ${menuItems.imports.join("\n")} - export default { - ${menuItems.code}, - } - ` + ${ + pluginMode + ? `const menuItemModule = { ${menuItems.code} }` + : `export default { ${menuItems.code} }` + } + ` return generateModule(code) } diff --git a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-route-module.ts b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-route-module.ts index 91d44e5614..1a0df1455d 100644 --- a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-route-module.ts +++ b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-route-module.ts @@ -2,7 +2,10 @@ import { outdent } from "outdent" import { generateRoutes } from "../routes" import { generateModule } from "../utils" -export async function generateVirtualRouteModule(sources: Set) { +export async function generateVirtualRouteModule( + sources: Set, + pluginMode = false +) { const routes = await generateRoutes(sources) const imports = [...routes.imports] @@ -10,8 +13,10 @@ export async function generateVirtualRouteModule(sources: Set) { const code = outdent` ${imports.join("\n")} - export default { - ${routes.code} + ${ + pluginMode + ? `const routeModule = { ${routes.code} }` + : `export default { ${routes.code} }` } ` diff --git a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-widget-module.ts b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-widget-module.ts index fef19bb4c7..b4a3d58def 100644 --- a/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-widget-module.ts +++ b/packages/admin/admin-vite-plugin/src/virtual-modules/generate-virtual-widget-module.ts @@ -2,7 +2,10 @@ import outdent from "outdent" import { generateModule } from "../utils" import { generateWidgets } from "../widgets" -export async function generateVirtualWidgetModule(sources: Set) { +export async function generateVirtualWidgetModule( + sources: Set, + pluginMode = false +) { const widgets = await generateWidgets(sources) const imports = [...widgets.imports] @@ -10,8 +13,10 @@ export async function generateVirtualWidgetModule(sources: Set) { const code = outdent` ${imports.join("\n")} - export default { - ${widgets.code}, + ${ + pluginMode + ? `const widgetModule = { ${widgets.code} }` + : `export default { ${widgets.code} }` } ` diff --git a/packages/admin/dashboard/package.json b/packages/admin/dashboard/package.json index ec8d2d27a2..0d6ad7e4ca 100644 --- a/packages/admin/dashboard/package.json +++ b/packages/admin/dashboard/package.json @@ -36,7 +36,6 @@ "files": [ "package.json", "src", - "index.html", "dist" ], "dependencies": { diff --git a/packages/admin/dashboard/scripts/generate-types.js b/packages/admin/dashboard/scripts/generate-types.js index 097a86c1d5..18e154396f 100644 --- a/packages/admin/dashboard/scripts/generate-types.js +++ b/packages/admin/dashboard/scripts/generate-types.js @@ -11,12 +11,12 @@ async function generateTypes() { const filePath = path.join(distDir, "index.d.ts") const fileContent = ` -import * as react_jsx_runtime from "react/jsx-runtime" + declare function App(props: { + plugins?: any[] + }): JSX.Element -declare const App: () => react_jsx_runtime.JSX.Element - -export default App -` + export default App + ` // Ensure the dist directory exists if (!fs.existsSync(distDir)) { diff --git a/packages/admin/dashboard/src/app.tsx b/packages/admin/dashboard/src/app.tsx index 855bcfbaf0..7f46055724 100644 --- a/packages/admin/dashboard/src/app.tsx +++ b/packages/admin/dashboard/src/app.tsx @@ -1,27 +1,32 @@ -import { DashboardExtensionManager } from "./extensions" -import { Providers } from "./providers/providers" -import { RouterProvider } from "./providers/router-provider" +import { DashboardApp } from "./dashboard-app" +import { DashboardPlugin } from "./dashboard-app/types" import displayModule from "virtual:medusa/displays" import formModule from "virtual:medusa/forms" import menuItemModule from "virtual:medusa/menu-items" +import routeModule from "virtual:medusa/routes" import widgetModule from "virtual:medusa/widgets" import "./index.css" -function App() { - const manager = new DashboardExtensionManager({ - displayModule, - formModule, - menuItemModule, - widgetModule, +const localPlugin = { + widgetModule, + routeModule, + displayModule, + formModule, + menuItemModule, +} + +interface AppProps { + plugins?: DashboardPlugin[] +} + +function App({ plugins = [] }: AppProps) { + const app = new DashboardApp({ + plugins: [localPlugin, ...plugins], }) - return ( - - - - ) + return
{app.render()}
} export default App diff --git a/packages/admin/dashboard/src/components/layout/main-layout/main-layout.tsx b/packages/admin/dashboard/src/components/layout/main-layout/main-layout.tsx index ca406063bc..272808f331 100644 --- a/packages/admin/dashboard/src/components/layout/main-layout/main-layout.tsx +++ b/packages/admin/dashboard/src/components/layout/main-layout/main-layout.tsx @@ -24,9 +24,9 @@ import { INavItem, NavItem } from "../../layout/nav-item" import { Shell } from "../../layout/shell" import { Link, useLocation, useNavigate } from "react-router-dom" -import { useDashboardExtension } from "../../../extensions" import { useLogout } from "../../../hooks/api" import { queryClient } from "../../../lib/query-client" +import { useExtension } from "../../../providers/extension-provider" import { useSearch } from "../../../providers/search-provider" import { UserMenu } from "../user-menu" @@ -283,7 +283,7 @@ const Searchbar = () => { const CoreRouteSection = () => { const coreRoutes = useCoreRoutes() - const { getMenu } = useDashboardExtension() + const { getMenu } = useExtension() const menuItems = getMenu("coreExtensions") @@ -308,7 +308,7 @@ const CoreRouteSection = () => { const ExtensionRouteSection = () => { const { t } = useTranslation() - const { getMenu } = useDashboardExtension() + const { getMenu } = useExtension() const menuItems = getMenu("coreExtensions").filter((item) => !item.nested) diff --git a/packages/admin/dashboard/src/components/layout/nav-item/nav-item.tsx b/packages/admin/dashboard/src/components/layout/nav-item/nav-item.tsx index 66c4fc0822..5ef7be021c 100644 --- a/packages/admin/dashboard/src/components/layout/nav-item/nav-item.tsx +++ b/packages/admin/dashboard/src/components/layout/nav-item/nav-item.tsx @@ -130,7 +130,7 @@ export const NavItem = ({ i.to === pathname)} state={ from ? { diff --git a/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx b/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx index ac4db2666e..dfdc4900c5 100644 --- a/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx +++ b/packages/admin/dashboard/src/components/layout/settings-layout/settings-layout.tsx @@ -5,10 +5,9 @@ import { Fragment, useEffect, useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { Link, useLocation } from "react-router-dom" +import { useExtension } from "../../../providers/extension-provider" import { INavItem, NavItem } from "../nav-item" import { Shell } from "../shell" - -import { useDashboardExtension } from "../../../extensions" import { UserMenu } from "../user-menu" export const SettingsLayout = () => { @@ -114,7 +113,7 @@ const getSafeFromValue = (from: string) => { } const SettingsSidebar = () => { - const { getMenu } = useDashboardExtension() + const { getMenu } = useExtension() const routes = useSettingRoutes() const developerRoutes = useDeveloperRoutes() diff --git a/packages/admin/dashboard/src/extensions/dashboard-extension-manager/dashboard-extension-manager.tsx b/packages/admin/dashboard/src/dashboard-app/dashboard-app.tsx similarity index 56% rename from packages/admin/dashboard/src/extensions/dashboard-extension-manager/dashboard-extension-manager.tsx rename to packages/admin/dashboard/src/dashboard-app/dashboard-app.tsx index 8302778b7f..2e2f23b3f1 100644 --- a/packages/admin/dashboard/src/extensions/dashboard-extension-manager/dashboard-extension-manager.tsx +++ b/packages/admin/dashboard/src/dashboard-app/dashboard-app.tsx @@ -7,87 +7,123 @@ import { NESTED_ROUTE_POSITIONS, } from "@medusajs/admin-shared" import * as React from "react" -import { INavItem } from "../../components/layout/nav-item" +import { + createBrowserRouter, + RouteObject, + RouterProvider, +} from "react-router-dom" +import { INavItem } from "../components/layout/nav-item" +import { Providers } from "../providers" +import { getRouteMap } from "./routes/get-route.map" +import { createRouteMap, getRouteExtensions } from "./routes/utils" import { ConfigExtension, ConfigField, ConfigFieldMap, + DashboardPlugin, DisplayExtension, DisplayMap, - DisplayModule, FormExtension, FormField, FormFieldExtension, FormFieldMap, - FormModule, FormZoneMap, MenuItemExtension, MenuItemKey, - MenuItemModule, - WidgetExtension, - WidgetModule, + MenuMap, + WidgetMap, ZoneStructure, -} from "../types" +} from "./types" -export type DashboardExtensionManagerProps = { - formModule: FormModule - displayModule: DisplayModule - menuItemModule: MenuItemModule - widgetModule: WidgetModule +type DashboardAppProps = { + plugins: DashboardPlugin[] } -export class DashboardExtensionManager { - private widgets: Map - private menus: Map +export class DashboardApp { + private widgets: WidgetMap + private menus: MenuMap private fields: FormFieldMap private configs: ConfigFieldMap private displays: DisplayMap + private coreRoutes: RouteObject[] + private settingsRoutes: RouteObject[] - constructor({ - widgetModule, - menuItemModule, - displayModule, - formModule, - }: DashboardExtensionManagerProps) { - this.widgets = this.populateWidgets(widgetModule.widgets) - this.menus = this.populateMenus(menuItemModule.menuItems) + constructor({ plugins }: DashboardAppProps) { + this.widgets = this.populateWidgets(plugins) + this.menus = this.populateMenus(plugins) - const { fields, configs } = this.populateForm(formModule) + const { coreRoutes, settingsRoutes } = this.populateRoutes(plugins) + this.coreRoutes = coreRoutes + this.settingsRoutes = settingsRoutes + + const { fields, configs } = this.populateForm(plugins) this.fields = fields this.configs = configs - this.displays = this.populateDisplays(displayModule) + this.displays = this.populateDisplays(plugins) } - private populateWidgets(widgets: WidgetExtension[] | undefined) { - const registry = new Map() + private populateRoutes(plugins: DashboardPlugin[]) { + const coreRoutes: RouteObject[] = [] + const settingsRoutes: RouteObject[] = [] - if (!widgets) { - return registry + for (const plugin of plugins) { + const filteredCoreRoutes = getRouteExtensions(plugin.routeModule, "core") + const filteredSettingsRoutes = getRouteExtensions( + plugin.routeModule, + "settings" + ) + + const coreRoutesMap = createRouteMap(filteredCoreRoutes) + const settingsRoutesMap = createRouteMap(filteredSettingsRoutes) + + coreRoutes.push(...coreRoutesMap) + settingsRoutes.push(...settingsRoutesMap) } - widgets.forEach((widget) => { - widget.zone.forEach((zone) => { - if (!registry.has(zone)) { - registry.set(zone, []) - } - registry.get(zone)!.push(widget.Component) + return { coreRoutes, settingsRoutes } + } + + private populateWidgets(plugins: DashboardPlugin[]) { + const registry = new Map() + + plugins.forEach((plugin) => { + const widgets = plugin.widgetModule.widgets + if (!widgets) { + return + } + + widgets.forEach((widget) => { + widget.zone.forEach((zone) => { + if (!registry.has(zone)) { + registry.set(zone, []) + } + registry.get(zone)!.push(widget.Component) + }) }) }) return registry } - private populateMenus(menuItems: MenuItemExtension[] | undefined) { + private populateMenus(plugins: DashboardPlugin[]) { const registry = new Map() const tempRegistry: Record = {} - if (!menuItems) { + // Collect all menu items from all plugins + const allMenuItems: MenuItemExtension[] = [] + plugins.forEach((plugin) => { + if (plugin.menuItemModule.menuItems) { + allMenuItems.push(...plugin.menuItemModule.menuItems) + } + }) + + if (allMenuItems.length === 0) { return registry } - menuItems.sort((a, b) => a.path.length - b.path.length) + allMenuItems.sort((a, b) => a.path.length - b.path.length) - menuItems.forEach((item) => { + allMenuItems.forEach((item) => { if (item.path.includes("/:")) { if (process.env.NODE_ENV === "development") { console.warn( @@ -114,7 +150,7 @@ export class DashboardExtensionManager { } // Find the parent item if it exists - const parentItem = menuItems.find( + const parentItem = allMenuItems.find( (menuItem) => menuItem.path === parentPath ) @@ -158,25 +194,62 @@ export class DashboardExtensionManager { return registry } - private populateForm(formModule: FormModule): { + private populateForm(plugins: DashboardPlugin[]): { fields: FormFieldMap configs: ConfigFieldMap } { const fields: FormFieldMap = new Map() const configs: ConfigFieldMap = new Map() - Object.entries(formModule.customFields).forEach( - ([model, customization]) => { - fields.set( - model as CustomFieldModel, - this.processFields(customization.forms) - ) - configs.set( - model as CustomFieldModel, - this.processConfigs(customization.configs) - ) - } - ) + plugins.forEach((plugin) => { + Object.entries(plugin.formModule.customFields).forEach( + ([model, customization]) => { + // Initialize maps if they don't exist for this model + if (!fields.has(model as CustomFieldModel)) { + fields.set(model as CustomFieldModel, new Map()) + } + if (!configs.has(model as CustomFieldModel)) { + configs.set(model as CustomFieldModel, new Map()) + } + + // Process forms + const modelFields = this.processFields(customization.forms) + const existingModelFields = fields.get(model as CustomFieldModel)! + + // Merge the maps + modelFields.forEach((zoneStructure, zone) => { + if (!existingModelFields.has(zone)) { + existingModelFields.set(zone, { components: [], tabs: new Map() }) + } + + const existingZoneStructure = existingModelFields.get(zone)! + + // Merge components + existingZoneStructure.components.push(...zoneStructure.components) + + // Merge tabs + zoneStructure.tabs.forEach((fields, tab) => { + if (!existingZoneStructure.tabs.has(tab)) { + existingZoneStructure.tabs.set(tab, []) + } + existingZoneStructure.tabs.get(tab)!.push(...fields) + }) + }) + + // Process configs + const modelConfigs = this.processConfigs(customization.configs) + const existingModelConfigs = configs.get(model as CustomFieldModel)! + + // Merge the config maps + modelConfigs.forEach((configFields, zone) => { + if (!existingModelConfigs.has(zone)) { + existingModelConfigs.set(zone, []) + } + existingModelConfigs.get(zone)!.push(...configFields) + }) + } + ) + }) return { fields, configs } } @@ -269,16 +342,36 @@ export class DashboardExtensionManager { } } - private populateDisplays(displayModule: DisplayModule): DisplayMap { + private populateDisplays(plugins: DashboardPlugin[]): DisplayMap { const displays = new Map< CustomFieldModel, Map[]> >() - Object.entries(displayModule.displays).forEach(([model, customization]) => { - displays.set( - model as CustomFieldModel, - this.processDisplays(customization) + plugins.forEach((plugin) => { + Object.entries(plugin.displayModule.displays).forEach( + ([model, customization]) => { + if (!displays.has(model as CustomFieldModel)) { + displays.set( + model as CustomFieldModel, + new Map< + CustomFieldContainerZone, + React.ComponentType<{ data: any }>[] + >() + ) + } + + const modelDisplays = displays.get(model as CustomFieldModel)! + const processedDisplays = this.processDisplays(customization) + + // Merge the displays + processedDisplays.forEach((components, zone) => { + if (!modelDisplays.has(zone)) { + modelDisplays.set(zone, []) + } + modelDisplays.get(zone)!.push(...components) + }) + } ) }) @@ -347,4 +440,21 @@ export class DashboardExtensionManager { getDisplays: this.getDisplays.bind(this), } } + + render() { + const routes = getRouteMap({ + settingsRoutes: this.settingsRoutes, + coreRoutes: this.coreRoutes, + }) + + const router = createBrowserRouter(routes, { + basename: __BASE__ || "/", + }) + + return ( + + + + ) + } } diff --git a/packages/admin/dashboard/src/extensions/forms/form-extension-zone/form-extension-zone.tsx b/packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/form-extension-zone.tsx similarity index 100% rename from packages/admin/dashboard/src/extensions/forms/form-extension-zone/form-extension-zone.tsx rename to packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/form-extension-zone.tsx diff --git a/packages/admin/dashboard/src/extensions/forms/form-extension-zone/index.ts b/packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/index.ts similarity index 100% rename from packages/admin/dashboard/src/extensions/forms/form-extension-zone/index.ts rename to packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/index.ts diff --git a/packages/admin/dashboard/src/extensions/forms/form-extension-zone/types.ts b/packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/types.ts similarity index 100% rename from packages/admin/dashboard/src/extensions/forms/form-extension-zone/types.ts rename to packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/types.ts diff --git a/packages/admin/dashboard/src/extensions/forms/form-extension-zone/utils.ts b/packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/utils.ts similarity index 100% rename from packages/admin/dashboard/src/extensions/forms/form-extension-zone/utils.ts rename to packages/admin/dashboard/src/dashboard-app/forms/form-extension-zone/utils.ts diff --git a/packages/admin/dashboard/src/extensions/forms/hooks.tsx b/packages/admin/dashboard/src/dashboard-app/forms/hooks.tsx similarity index 100% rename from packages/admin/dashboard/src/extensions/forms/hooks.tsx rename to packages/admin/dashboard/src/dashboard-app/forms/hooks.tsx diff --git a/packages/admin/dashboard/src/extensions/forms/index.ts b/packages/admin/dashboard/src/dashboard-app/forms/index.ts similarity index 100% rename from packages/admin/dashboard/src/extensions/forms/index.ts rename to packages/admin/dashboard/src/dashboard-app/forms/index.ts diff --git a/packages/admin/dashboard/src/extensions/index.ts b/packages/admin/dashboard/src/dashboard-app/index.ts similarity index 70% rename from packages/admin/dashboard/src/extensions/index.ts rename to packages/admin/dashboard/src/dashboard-app/index.ts index dd3e29f290..7136950301 100644 --- a/packages/admin/dashboard/src/extensions/index.ts +++ b/packages/admin/dashboard/src/dashboard-app/index.ts @@ -1,5 +1,4 @@ -export * from "./dashboard-extension-manager" -export * from "./dashboard-extension-provider" +export * from "./dashboard-app" export * from "./forms" export * from "./links/utils" export * from "./routes/utils" diff --git a/packages/admin/dashboard/src/extensions/links/utils.ts b/packages/admin/dashboard/src/dashboard-app/links/utils.ts similarity index 100% rename from packages/admin/dashboard/src/extensions/links/utils.ts rename to packages/admin/dashboard/src/dashboard-app/links/utils.ts diff --git a/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx b/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx new file mode 100644 index 0000000000..ee3de99151 --- /dev/null +++ b/packages/admin/dashboard/src/dashboard-app/routes/get-route.map.tsx @@ -0,0 +1,1735 @@ +import { HttpTypes } from "@medusajs/types" +import { t } from "i18next" +import { Outlet, RouteObject, UIMatch } from "react-router-dom" +import { ProtectedRoute } from "../../components/authentication/protected-route" +import { MainLayout } from "../../components/layout/main-layout" +import { PublicLayout } from "../../components/layout/public-layout" +import { SettingsLayout } from "../../components/layout/settings-layout" +import { ErrorBoundary } from "../../components/utilities/error-boundary" +import { TaxRegionDetailBreadcrumb } from "../../routes/tax-regions/tax-region-detail/breadcrumb" +import { taxRegionLoader } from "../../routes/tax-regions/tax-region-detail/loader" + +export function getRouteMap({ + settingsRoutes, + coreRoutes, +}: { + settingsRoutes: RouteObject[] + coreRoutes: RouteObject[] +}) { + return [ + { + element: , + errorElement: , + children: [ + { + element: , + children: [ + { + path: "/", + errorElement: , + lazy: () => import("../../routes/home"), + }, + { + path: "/products", + errorElement: , + handle: { + breadcrumb: () => t("products.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/products/product-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/products/product-create"), + }, + { + path: "import", + lazy: () => + import("../../routes/products/product-import"), + }, + { + path: "export", + lazy: () => + import("../../routes/products/product-export"), + }, + ], + }, + { + path: ":id", + errorElement: , + lazy: async () => { + const { Breadcrumb, loader } = await import( + "../../routes/products/product-detail" + ) + + return { + Component: Outlet, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/products/product-detail"), + children: [ + { + path: "edit", + lazy: () => + import("../../routes/products/product-edit"), + }, + { + path: "edit-variant", + lazy: () => + import( + "../../routes/product-variants/product-variant-edit" + ), + }, + { + path: "sales-channels", + lazy: () => + import( + "../../routes/products/product-sales-channels" + ), + }, + { + path: "attributes", + lazy: () => + import("../../routes/products/product-attributes"), + }, + { + path: "organization", + lazy: () => + import( + "../../routes/products/product-organization" + ), + }, + { + path: "shipping-profile", + lazy: () => + import( + "../../routes/products/product-shipping-profile" + ), + }, + { + path: "media", + lazy: () => + import("../../routes/products/product-media"), + }, + { + path: "prices", + lazy: () => + import("../../routes/products/product-prices"), + }, + { + path: "options/create", + lazy: () => + import( + "../../routes/products/product-create-option" + ), + }, + { + path: "options/:option_id/edit", + lazy: () => + import("../../routes/products/product-edit-option"), + }, + { + path: "variants/create", + lazy: () => + import( + "../../routes/products/product-create-variant" + ), + }, + { + path: "stock", + lazy: () => + import("../../routes/products/product-stock"), + }, + { + path: "metadata/edit", + lazy: () => + import("../../routes/products/product-metadata"), + }, + ], + }, + { + path: "variants/:variant_id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/product-variants/product-variant-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + // eslint-disable-next-line max-len + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/product-variants/product-variant-edit" + ), + }, + { + path: "prices", + lazy: () => + import("../../routes/products/product-prices"), + }, + { + path: "manage-items", + lazy: () => + import( + "../../routes/product-variants/product-variant-manage-inventory-items" + ), + }, + { + path: "metadata/edit", + lazy: () => + import( + "../../routes/product-variants/product-variant-metadata" + ), + }, + ], + }, + ], + }, + ], + }, + { + path: "/categories", + errorElement: , + handle: { + breadcrumb: () => t("categories.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/categories/category-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/categories/category-create"), + }, + { + path: "organize", + lazy: () => + import("../../routes/categories/category-organize"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/categories/category-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/categories/category-edit"), + }, + { + path: "products", + lazy: () => + import("../../routes/categories/category-products"), + }, + { + path: "organize", + lazy: () => + import("../../routes/categories/category-organize"), + }, + { + path: "metadata/edit", + lazy: () => + import("../../routes/categories/categories-metadata"), + }, + ], + }, + ], + }, + { + path: "/orders", + errorElement: , + handle: { + breadcrumb: () => t("orders.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/orders/order-list"), + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/orders/order-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "fulfillment", + lazy: () => + import("../../routes/orders/order-create-fulfillment"), + }, + { + path: "returns/:return_id/receive", + lazy: () => + import("../../routes/orders/order-receive-return"), + }, + { + path: "allocate-items", + lazy: () => + import("../../routes/orders/order-allocate-items"), + }, + { + path: ":f_id/create-shipment", + lazy: () => + import("../../routes/orders/order-create-shipment"), + }, + { + path: "returns", + lazy: () => + import("../../routes/orders/order-create-return"), + }, + { + path: "claims", + lazy: () => + import("../../routes/orders/order-create-claim"), + }, + { + path: "exchanges", + lazy: () => + import("../../routes/orders/order-create-exchange"), + }, + { + path: "edits", + lazy: () => + import("../../routes/orders/order-create-edit"), + }, + { + path: "refund", + lazy: () => + import("../../routes/orders/order-create-refund"), + }, + { + path: "transfer", + lazy: () => + import("../../routes/orders/order-request-transfer"), + }, + { + path: "email", + lazy: () => + import("../../routes/orders/order-edit-email"), + }, + { + path: "shipping-address", + lazy: () => + import( + "../../routes/orders/order-edit-shipping-address" + ), + }, + { + path: "billing-address", + lazy: () => + import( + "../../routes/orders/order-edit-billing-address" + ), + }, + { + path: "metadata/edit", + lazy: () => import("../../routes/orders/order-metadata"), + }, + ], + }, + ], + }, + { + path: "/promotions", + errorElement: , + handle: { + breadcrumb: () => t("promotions.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/promotions/promotion-list"), + }, + { + path: "create", + lazy: () => + import("../../routes/promotions/promotion-create"), + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/promotions/promotion-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/promotions/promotion-edit-details" + ), + }, + { + path: "add-to-campaign", + lazy: () => + import( + "../../routes/promotions/promotion-add-campaign" + ), + }, + { + path: ":ruleType/edit", + lazy: () => + import("../../routes/promotions/common/edit-rules"), + }, + ], + }, + ], + }, + { + path: "/campaigns", + errorElement: , + handle: { + breadcrumb: () => t("campaigns.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/campaigns/campaign-list"), + children: [], + }, + { + path: "create", + lazy: () => import("../../routes/campaigns/campaign-create"), + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/campaigns/campaign-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/campaigns/campaign-edit"), + }, + { + path: "configuration", + lazy: () => + import("../../routes/campaigns/campaign-configuration"), + }, + { + path: "edit-budget", + lazy: () => + import("../../routes/campaigns/campaign-budget-edit"), + }, + { + path: "add-promotions", + lazy: () => + import( + "../../routes/campaigns/add-campaign-promotions" + ), + }, + ], + }, + ], + }, + { + path: "/collections", + errorElement: , + handle: { + breadcrumb: () => t("collections.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/collections/collection-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/collections/collection-create"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/collections/collection-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/collections/collection-edit"), + }, + { + path: "products", + lazy: () => + import( + "../../routes/collections/collection-add-products" + ), + }, + { + path: "metadata/edit", + lazy: () => + import("../../routes/collections/collection-metadata"), + }, + ], + }, + ], + }, + { + path: "/price-lists", + errorElement: , + handle: { + breadcrumb: () => t("priceLists.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/price-lists/price-list-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/price-lists/price-list-create"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/price-lists/price-list-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/price-lists/price-list-edit"), + }, + { + path: "configuration", + lazy: () => + import( + "../../routes/price-lists/price-list-configuration" + ), + }, + { + path: "products/add", + lazy: () => + import( + "../../routes/price-lists/price-list-prices-add" + ), + }, + { + path: "products/edit", + lazy: () => + import( + "../../routes/price-lists/price-list-prices-edit" + ), + }, + ], + }, + ], + }, + { + path: "/customers", + errorElement: , + handle: { + breadcrumb: () => t("customers.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/customers/customer-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/customers/customer-create"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/customers/customer-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/customers/customer-edit"), + }, + { + path: "add-customer-groups", + lazy: () => + import( + "../../routes/customers/customers-add-customer-group" + ), + }, + { + path: ":order_id/transfer", + lazy: () => + import("../../routes/orders/order-request-transfer"), + }, + { + path: "metadata/edit", + lazy: () => + import("../../routes/customers/customer-metadata"), + }, + ], + }, + ], + }, + { + path: "/customer-groups", + errorElement: , + handle: { + breadcrumb: () => t("customerGroups.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/customer-groups/customer-group-list"), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/customer-groups/customer-group-create" + ), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/customer-groups/customer-group-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/customer-groups/customer-group-edit" + ), + }, + { + path: "add-customers", + lazy: () => + import( + "../../routes/customer-groups/customer-group-add-customers" + ), + }, + { + path: "metadata/edit", + lazy: () => + import( + "../../routes/customer-groups/customer-group-metadata" + ), + }, + ], + }, + ], + }, + { + path: "/reservations", + errorElement: , + handle: { + breadcrumb: () => t("reservations.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/reservations/reservation-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/reservations/reservation-create"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/reservations/reservation-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/reservations/reservation-detail/components/edit-reservation" + ), + }, + { + path: "metadata/edit", + lazy: () => + import( + "../../routes/reservations/reservation-metadata" + ), + }, + ], + }, + ], + }, + { + path: "/inventory", + errorElement: , + handle: { + breadcrumb: () => t("inventory.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/inventory/inventory-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/inventory/inventory-create"), + }, + { + path: "stock", + lazy: () => + import("../../routes/inventory/inventory-stock"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/inventory/inventory-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/inventory/inventory-detail/components/edit-inventory-item" + ), + }, + { + path: "attributes", + lazy: () => + import( + "../../routes/inventory/inventory-detail/components/edit-inventory-item-attributes" + ), + }, + { + path: "metadata/edit", + lazy: () => + import("../../routes/inventory/inventory-metadata"), + }, + { + path: "locations", + lazy: () => + import( + "../../routes/inventory/inventory-detail/components/manage-locations" + ), + }, + { + path: "locations/:location_id", + lazy: () => + import( + "../../routes/inventory/inventory-detail/components/adjust-inventory" + ), + }, + ], + }, + ], + }, + ...coreRoutes, + ], + }, + ], + }, + { + element: , + errorElement: , + children: [ + { + path: "/settings", + handle: { + breadcrumb: () => t("app.nav.settings.header"), + }, + element: , + children: [ + { + index: true, + errorElement: , + lazy: () => import("../../routes/settings"), + }, + { + path: "profile", + errorElement: , + lazy: () => import("../../routes/profile/profile-detail"), + handle: { + breadcrumb: () => t("profile.domain"), + }, + children: [ + { + path: "edit", + lazy: () => import("../../routes/profile/profile-edit"), + }, + ], + }, + { + path: "regions", + errorElement: , + element: , + handle: { + breadcrumb: () => t("regions.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/regions/region-list"), + children: [ + { + path: "create", + lazy: () => import("../../routes/regions/region-create"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/regions/region-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => import("../../routes/regions/region-edit"), + }, + { + path: "countries/add", + lazy: () => + import("../../routes/regions/region-add-countries"), + }, + { + path: "metadata/edit", + lazy: () => + import("../../routes/regions/region-metadata"), + }, + ], + }, + ], + }, + { + path: "store", + errorElement: , + lazy: () => import("../../routes/store/store-detail"), + handle: { + breadcrumb: () => t("store.domain"), + }, + children: [ + { + path: "edit", + lazy: () => import("../../routes/store/store-edit"), + }, + { + path: "currencies", + lazy: () => import("../../routes/store/store-add-currencies"), + }, + { + path: "metadata/edit", + lazy: () => import("../../routes/store/store-metadata"), + }, + ], + }, + { + path: "users", + errorElement: , + element: , + handle: { + breadcrumb: () => t("users.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/users/user-list"), + children: [ + { + path: "invite", + lazy: () => import("../../routes/users/user-invite"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/users/user-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => import("../../routes/users/user-edit"), + }, + { + path: "metadata/edit", + lazy: () => import("../../routes/users/user-metadata"), + }, + ], + }, + ], + }, + { + path: "sales-channels", + errorElement: , + element: , + handle: { + breadcrumb: () => t("salesChannels.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/sales-channels/sales-channel-list"), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/sales-channels/sales-channel-create" + ), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/sales-channels/sales-channel-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/sales-channels/sales-channel-edit" + ), + }, + { + path: "add-products", + lazy: () => + import( + "../../routes/sales-channels/sales-channel-add-products" + ), + }, + { + path: "metadata/edit", + lazy: () => + import( + "../../routes/sales-channels/sales-channel-metadata" + ), + }, + ], + }, + ], + }, + { + path: "locations", + errorElement: , + element: , + handle: { + breadcrumb: () => t("locations.domain"), + }, + children: [ + { + path: "", + lazy: () => import("../../routes/locations/location-list"), + }, + { + path: "create", + lazy: () => import("../../routes/locations/location-create"), + }, + { + path: "shipping-profiles", + element: , + handle: { + breadcrumb: () => t("shippingProfile.domain"), + }, + children: [ + { + path: "", + lazy: () => + import( + "../../routes/shipping-profiles/shipping-profiles-list" + ), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/shipping-profiles/shipping-profile-create" + ), + }, + ], + }, + { + path: ":shipping_profile_id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/shipping-profiles/shipping-profile-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + // eslint-disable-next-line max-len + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "metadata/edit", + lazy: () => + import( + "../../routes/shipping-profiles/shipping-profile-metadata" + ), + }, + ], + }, + ], + }, + { + path: ":location_id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/locations/location-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/locations/location-edit"), + }, + { + path: "sales-channels", + lazy: () => + import( + "../../routes/locations/location-sales-channels" + ), + }, + { + path: "fulfillment-providers", + lazy: () => + import( + "../../routes/locations/location-fulfillment-providers" + ), + }, + { + path: "fulfillment-set/:fset_id", + children: [ + { + path: "service-zones/create", + lazy: () => + import( + "../../routes/locations/location-service-zone-create" + ), + }, + { + path: "service-zone/:zone_id", + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/locations/location-service-zone-edit" + ), + }, + { + path: "areas", + lazy: () => + import( + "../../routes/locations/location-service-zone-manage-areas" + ), + }, + { + path: "shipping-option", + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/locations/location-service-zone-shipping-option-create" + ), + }, + { + path: ":so_id", + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/locations/location-service-zone-shipping-option-edit" + ), + }, + { + path: "pricing", + lazy: () => + import( + "../../routes/locations/location-service-zone-shipping-option-pricing" + ), + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + path: "product-tags", + errorElement: , + element: , + handle: { + breadcrumb: () => t("productTags.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/product-tags/product-tag-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/product-tags/product-tag-create"), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/product-tags/product-tag-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/product-tags/product-tag-edit"), + }, + ], + }, + ], + }, + { + path: "workflows", + errorElement: , + element: , + handle: { + breadcrumb: () => t("workflowExecutions.domain"), + }, + children: [ + { + path: "", + lazy: () => + import( + "../../routes/workflow-executions/workflow-execution-list" + ), + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/workflow-executions/workflow-execution-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + // eslint-disable-next-line max-len + match: UIMatch + ) => , + }, + } + }, + }, + ], + }, + { + path: "product-types", + errorElement: , + element: , + handle: { + breadcrumb: () => t("productTypes.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/product-types/product-type-list"), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/product-types/product-type-create" + ), + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/product-types/product-type-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/product-types/product-type-edit"), + }, + ], + }, + ], + }, + { + path: "publishable-api-keys", + element: , + handle: { + breadcrumb: () => t("apiKeyManagement.domain.publishable"), + }, + children: [ + { + path: "", + element: , + children: [ + { + path: "", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-list" + ), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-create" + ), + }, + ], + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/api-key-management/api-key-management-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-edit" + ), + }, + { + path: "sales-channels", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-sales-channels" + ), + }, + ], + }, + ], + }, + { + path: "secret-api-keys", + element: , + handle: { + breadcrumb: () => t("apiKeyManagement.domain.secret"), + }, + children: [ + { + path: "", + element: , + children: [ + { + path: "", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-list" + ), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-create" + ), + }, + ], + }, + ], + }, + { + path: ":id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/api-key-management/api-key-management-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/api-key-management/api-key-management-edit" + ), + }, + ], + }, + ], + }, + { + path: "tax-regions", + element: , + handle: { + breadcrumb: () => t("taxRegions.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/tax-regions/tax-region-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/tax-regions/tax-region-create"), + }, + ], + }, + { + path: ":id", + Component: Outlet, + loader: taxRegionLoader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + children: [ + { + path: "", + lazy: async () => { + const { Component } = await import( + "../../routes/tax-regions/tax-region-detail" + ) + + return { + Component, + } + }, + children: [ + { + path: "provinces/create", + lazy: () => + import( + "../../routes/tax-regions/tax-region-province-create" + ), + }, + { + path: "overrides/create", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-override-create" + ), + }, + { + path: "overrides/:tax_rate_id/edit", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-override-edit" + ), + }, + { + path: "tax-rates/create", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-rate-create" + ), + }, + { + path: "tax-rates/:tax_rate_id/edit", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-rate-edit" + ), + }, + ], + }, + { + path: "provinces/:province_id", + lazy: async () => { + const { Component, Breadcrumb, loader } = await import( + "../../routes/tax-regions/tax-region-province-detail" + ) + + return { + Component, + loader, + handle: { + breadcrumb: ( + match: UIMatch + ) => , + }, + } + }, + children: [ + { + path: "tax-rates/create", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-rate-create" + ), + }, + { + path: "tax-rates/:tax_rate_id/edit", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-rate-edit" + ), + }, + { + path: "overrides/create", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-override-create" + ), + }, + { + path: "overrides/:tax_rate_id/edit", + lazy: () => + import( + "../../routes/tax-regions/tax-region-tax-override-edit" + ), + }, + ], + }, + ], + }, + ], + }, + { + path: "return-reasons", + element: , + handle: { + breadcrumb: () => t("returnReasons.domain"), + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/return-reasons/return-reason-list"), + children: [ + { + path: "create", + lazy: () => + import( + "../../routes/return-reasons/return-reason-create" + ), + }, + + { + path: ":id", + children: [ + { + path: "edit", + lazy: () => + import( + "../../routes/return-reasons/return-reason-edit" + ), + }, + ], + }, + ], + }, + ], + }, + ...settingsRoutes, + ], + }, + ], + }, + { + element: , + children: [ + { + errorElement: , + children: [ + { + path: "/login", + lazy: () => import("../../routes/login"), + }, + { + path: "/reset-password", + lazy: () => import("../../routes/reset-password"), + }, + { + path: "/invite", + lazy: () => import("../../routes/invite"), + }, + { + path: "*", + lazy: () => import("../../routes/no-match"), + }, + ], + }, + ], + }, + ] +} diff --git a/packages/admin/dashboard/src/extensions/routes/utils.ts b/packages/admin/dashboard/src/dashboard-app/routes/utils.ts similarity index 98% rename from packages/admin/dashboard/src/extensions/routes/utils.ts rename to packages/admin/dashboard/src/dashboard-app/routes/utils.ts index af2eb1aa60..d03f598a46 100644 --- a/packages/admin/dashboard/src/extensions/routes/utils.ts +++ b/packages/admin/dashboard/src/dashboard-app/routes/utils.ts @@ -137,7 +137,6 @@ const addRoute = ( if (!route) { route = createBranchRoute(currentSegment) - currentLevel.push(route) } const currentFullPath = fullPath @@ -157,8 +156,14 @@ const addRoute = ( route.handle = handle } + if (loader) { + route.loader = loader + } + leaf.children = processParallelRoutes(parallelRoutes, currentFullPath) route.children.push(leaf) + + currentLevel.push(route) } else { route.children ||= [] addRoute( diff --git a/packages/admin/dashboard/src/extensions/types.ts b/packages/admin/dashboard/src/dashboard-app/types.ts similarity index 87% rename from packages/admin/dashboard/src/extensions/types.ts rename to packages/admin/dashboard/src/dashboard-app/types.ts index 4d42070d69..7b3470f66e 100644 --- a/packages/admin/dashboard/src/extensions/types.ts +++ b/packages/admin/dashboard/src/dashboard-app/types.ts @@ -9,6 +9,7 @@ import { import { ComponentType } from "react" import { LoaderFunction } from "react-router-dom" import { ZodFirstPartySchemaTypes } from "zod" +import { INavItem } from "../components/layout/nav-item" export type RouteExtension = { Component: ComponentType @@ -119,3 +120,15 @@ export type DisplayMap = Map< CustomFieldModel, Map[]> > + +export type MenuMap = Map + +export type WidgetMap = Map + +export type DashboardPlugin = { + formModule: FormModule + displayModule: DisplayModule + menuItemModule: MenuItemModule + widgetModule: WidgetModule + routeModule: RouteModule +} diff --git a/packages/admin/dashboard/src/extensions/dashboard-extension-manager/index.ts b/packages/admin/dashboard/src/extensions/dashboard-extension-manager/index.ts deleted file mode 100644 index 456fea9b72..0000000000 --- a/packages/admin/dashboard/src/extensions/dashboard-extension-manager/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./dashboard-extension-manager"; - diff --git a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/dashboard-extension-context.tsx b/packages/admin/dashboard/src/extensions/dashboard-extension-provider/dashboard-extension-context.tsx deleted file mode 100644 index f3afbf0576..0000000000 --- a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/dashboard-extension-context.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { createContext } from "react" -import { DashboardExtensionManager } from "../dashboard-extension-manager" - -type DasboardExtenstionContextValue = DashboardExtensionManager["api"] - -export const DashboardExtensionContext = - createContext(null) diff --git a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/dashboard-extension-provider.tsx b/packages/admin/dashboard/src/extensions/dashboard-extension-provider/dashboard-extension-provider.tsx deleted file mode 100644 index 4efcb53787..0000000000 --- a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/dashboard-extension-provider.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { PropsWithChildren } from "react" -import { DashboardExtensionManager } from "../dashboard-extension-manager/dashboard-extension-manager" -import { DashboardExtensionContext } from "./dashboard-extension-context" - -type DashboardExtensionProviderProps = PropsWithChildren<{ - api: DashboardExtensionManager["api"] -}> - -export const DashboardExtensionProvider = ({ - api, - children, -}: DashboardExtensionProviderProps) => { - return ( - - {children} - - ) -} diff --git a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/index.ts b/packages/admin/dashboard/src/extensions/dashboard-extension-provider/index.ts deleted file mode 100644 index be9ca07a36..0000000000 --- a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { DashboardExtensionProvider } from "./dashboard-extension-provider" -export { useDashboardExtension } from "./use-dashboard-extension" diff --git a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/use-dashboard-extension.tsx b/packages/admin/dashboard/src/extensions/dashboard-extension-provider/use-dashboard-extension.tsx deleted file mode 100644 index 0c0a937188..0000000000 --- a/packages/admin/dashboard/src/extensions/dashboard-extension-provider/use-dashboard-extension.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useContext } from "react" -import { DashboardExtensionContext } from "./dashboard-extension-context" - -export const useDashboardExtension = () => { - const context = useContext(DashboardExtensionContext) - if (!context) { - throw new Error( - "useDashboardExtension must be used within a DashboardExtensionProvider" - ) - } - return context -} diff --git a/packages/admin/dashboard/src/index.ts b/packages/admin/dashboard/src/index.ts new file mode 100644 index 0000000000..be69b51b82 --- /dev/null +++ b/packages/admin/dashboard/src/index.ts @@ -0,0 +1,2 @@ +export type { DashboardPlugin } from "./dashboard-app/dashboard-app" +export * from "./render" diff --git a/packages/admin/dashboard/src/providers/extension-provider/extension-context.tsx b/packages/admin/dashboard/src/providers/extension-provider/extension-context.tsx new file mode 100644 index 0000000000..cc490788dc --- /dev/null +++ b/packages/admin/dashboard/src/providers/extension-provider/extension-context.tsx @@ -0,0 +1,8 @@ +import { createContext } from "react" +import { DashboardApp } from "../../dashboard-app" + +type ExtensionContextValue = DashboardApp["api"] + +export const ExtensionContext = createContext( + null +) diff --git a/packages/admin/dashboard/src/providers/extension-provider/extension-provider.tsx b/packages/admin/dashboard/src/providers/extension-provider/extension-provider.tsx new file mode 100644 index 0000000000..37da07743c --- /dev/null +++ b/packages/admin/dashboard/src/providers/extension-provider/extension-provider.tsx @@ -0,0 +1,18 @@ +import { PropsWithChildren } from "react" +import { DashboardApp } from "../../dashboard-app/dashboard-app" +import { ExtensionContext } from "./extension-context" + +type ExtensionProviderProps = PropsWithChildren<{ + api: DashboardApp["api"] +}> + +export const ExtensionProvider = ({ + api, + children, +}: ExtensionProviderProps) => { + return ( + + {children} + + ) +} diff --git a/packages/admin/dashboard/src/providers/extension-provider/index.ts b/packages/admin/dashboard/src/providers/extension-provider/index.ts new file mode 100644 index 0000000000..7bf5e76c40 --- /dev/null +++ b/packages/admin/dashboard/src/providers/extension-provider/index.ts @@ -0,0 +1,2 @@ +export { ExtensionProvider } from "./extension-provider" +export { useExtension } from "./use-extension" diff --git a/packages/admin/dashboard/src/providers/extension-provider/use-extension.tsx b/packages/admin/dashboard/src/providers/extension-provider/use-extension.tsx new file mode 100644 index 0000000000..bab2a8b2b1 --- /dev/null +++ b/packages/admin/dashboard/src/providers/extension-provider/use-extension.tsx @@ -0,0 +1,10 @@ +import { useContext } from "react" +import { ExtensionContext } from "./extension-context" + +export const useExtension = () => { + const context = useContext(ExtensionContext) + if (!context) { + throw new Error("useExtension must be used within a ExtensionProvider") + } + return context +} diff --git a/packages/admin/dashboard/src/providers/providers.tsx b/packages/admin/dashboard/src/providers/providers.tsx index c52ad0ad97..9386b4abcc 100644 --- a/packages/admin/dashboard/src/providers/providers.tsx +++ b/packages/admin/dashboard/src/providers/providers.tsx @@ -3,22 +3,20 @@ import { QueryClientProvider } from "@tanstack/react-query" import type { PropsWithChildren } from "react" import { HelmetProvider } from "react-helmet-async" import { I18n } from "../components/utilities/i18n" -import { - DashboardExtensionManager, - DashboardExtensionProvider, -} from "../extensions" +import { DashboardApp } from "../dashboard-app" import { queryClient } from "../lib/query-client" +import { ExtensionProvider } from "./extension-provider" import { I18nProvider } from "./i18n-provider" import { ThemeProvider } from "./theme-provider" type ProvidersProps = PropsWithChildren<{ - api: DashboardExtensionManager["api"] + api: DashboardApp["api"] }> export const Providers = ({ api, children }: ProvidersProps) => { return ( - + @@ -28,7 +26,7 @@ export const Providers = ({ api, children }: ProvidersProps) => { - + ) } diff --git a/packages/admin/dashboard/src/providers/router-provider/index.ts b/packages/admin/dashboard/src/providers/router-provider/index.ts deleted file mode 100644 index 997dca4e24..0000000000 --- a/packages/admin/dashboard/src/providers/router-provider/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./router-provider" diff --git a/packages/admin/dashboard/src/providers/router-provider/route-extensions.tsx b/packages/admin/dashboard/src/providers/router-provider/route-extensions.tsx deleted file mode 100644 index 4e66e8c472..0000000000 --- a/packages/admin/dashboard/src/providers/router-provider/route-extensions.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import routeModule from "virtual:medusa/routes" -import { - createRouteMap, - getRouteExtensions, -} from "../../extensions/routes/utils" - -const routes = getRouteExtensions(routeModule, "core") - -/** - * Core Route extensions. - */ -export const RouteExtensions = createRouteMap(routes) -console.log(RouteExtensions) diff --git a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx b/packages/admin/dashboard/src/providers/router-provider/route-map.tsx deleted file mode 100644 index d47846e10c..0000000000 --- a/packages/admin/dashboard/src/providers/router-provider/route-map.tsx +++ /dev/null @@ -1,1688 +0,0 @@ -import { HttpTypes } from "@medusajs/types" -import { Outlet, RouteObject, UIMatch } from "react-router-dom" - -import { t } from "i18next" -import { ProtectedRoute } from "../../components/authentication/protected-route" -import { MainLayout } from "../../components/layout/main-layout" -import { PublicLayout } from "../../components/layout/public-layout" -import { SettingsLayout } from "../../components/layout/settings-layout" -import { ErrorBoundary } from "../../components/utilities/error-boundary" -import { TaxRegionDetailBreadcrumb } from "../../routes/tax-regions/tax-region-detail/breadcrumb" -import { taxRegionLoader } from "../../routes/tax-regions/tax-region-detail/loader" -import { RouteExtensions } from "./route-extensions" -import { SettingsExtensions } from "./settings-extensions" - -export const RouteMap: RouteObject[] = [ - { - element: , - errorElement: , - children: [ - { - element: , - children: [ - { - path: "/", - errorElement: , - lazy: () => import("../../routes/home"), - }, - { - path: "/products", - errorElement: , - handle: { - breadcrumb: () => t("products.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/products/product-list"), - children: [ - { - path: "create", - lazy: () => import("../../routes/products/product-create"), - }, - { - path: "import", - lazy: () => import("../../routes/products/product-import"), - }, - { - path: "export", - lazy: () => import("../../routes/products/product-export"), - }, - ], - }, - { - path: ":id", - errorElement: , - lazy: async () => { - const { Breadcrumb, loader } = await import( - "../../routes/products/product-detail" - ) - - return { - Component: Outlet, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "", - lazy: () => import("../../routes/products/product-detail"), - children: [ - { - path: "edit", - lazy: () => - import("../../routes/products/product-edit"), - }, - { - path: "edit-variant", - lazy: () => - import( - "../../routes/product-variants/product-variant-edit" - ), - }, - { - path: "sales-channels", - lazy: () => - import( - "../../routes/products/product-sales-channels" - ), - }, - { - path: "attributes", - lazy: () => - import("../../routes/products/product-attributes"), - }, - { - path: "organization", - lazy: () => - import("../../routes/products/product-organization"), - }, - { - path: "shipping-profile", - lazy: () => - import( - "../../routes/products/product-shipping-profile" - ), - }, - { - path: "media", - lazy: () => - import("../../routes/products/product-media"), - }, - { - path: "prices", - lazy: () => - import("../../routes/products/product-prices"), - }, - { - path: "options/create", - lazy: () => - import("../../routes/products/product-create-option"), - }, - { - path: "options/:option_id/edit", - lazy: () => - import("../../routes/products/product-edit-option"), - }, - { - path: "variants/create", - lazy: () => - import( - "../../routes/products/product-create-variant" - ), - }, - { - path: "stock", - lazy: () => - import("../../routes/products/product-stock"), - }, - { - path: "metadata/edit", - lazy: () => - import("../../routes/products/product-metadata"), - }, - ], - }, - { - path: "variants/:variant_id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/product-variants/product-variant-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - // eslint-disable-next-line max-len - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/product-variants/product-variant-edit" - ), - }, - { - path: "prices", - lazy: () => - import("../../routes/products/product-prices"), - }, - { - path: "manage-items", - lazy: () => - import( - "../../routes/product-variants/product-variant-manage-inventory-items" - ), - }, - { - path: "metadata/edit", - lazy: () => - import( - "../../routes/product-variants/product-variant-metadata" - ), - }, - ], - }, - ], - }, - ], - }, - { - path: "/categories", - errorElement: , - handle: { - breadcrumb: () => t("categories.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/categories/category-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/categories/category-create"), - }, - { - path: "organize", - lazy: () => - import("../../routes/categories/category-organize"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/categories/category-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/categories/category-edit"), - }, - { - path: "products", - lazy: () => - import("../../routes/categories/category-products"), - }, - { - path: "organize", - lazy: () => - import("../../routes/categories/category-organize"), - }, - { - path: "metadata/edit", - lazy: () => - import("../../routes/categories/categories-metadata"), - }, - ], - }, - ], - }, - { - path: "/orders", - errorElement: , - handle: { - breadcrumb: () => t("orders.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/orders/order-list"), - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/orders/order-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "fulfillment", - lazy: () => - import("../../routes/orders/order-create-fulfillment"), - }, - { - path: "returns/:return_id/receive", - lazy: () => - import("../../routes/orders/order-receive-return"), - }, - { - path: "allocate-items", - lazy: () => - import("../../routes/orders/order-allocate-items"), - }, - { - path: ":f_id/create-shipment", - lazy: () => - import("../../routes/orders/order-create-shipment"), - }, - { - path: "returns", - lazy: () => - import("../../routes/orders/order-create-return"), - }, - { - path: "claims", - lazy: () => - import("../../routes/orders/order-create-claim"), - }, - { - path: "exchanges", - lazy: () => - import("../../routes/orders/order-create-exchange"), - }, - { - path: "edits", - lazy: () => import("../../routes/orders/order-create-edit"), - }, - { - path: "refund", - lazy: () => - import("../../routes/orders/order-create-refund"), - }, - { - path: "transfer", - lazy: () => - import("../../routes/orders/order-request-transfer"), - }, - { - path: "email", - lazy: () => import("../../routes/orders/order-edit-email"), - }, - { - path: "shipping-address", - lazy: () => - import("../../routes/orders/order-edit-shipping-address"), - }, - { - path: "billing-address", - lazy: () => - import("../../routes/orders/order-edit-billing-address"), - }, - { - path: "metadata/edit", - lazy: () => import("../../routes/orders/order-metadata"), - }, - ], - }, - ], - }, - { - path: "/promotions", - errorElement: , - handle: { - breadcrumb: () => t("promotions.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/promotions/promotion-list"), - }, - { - path: "create", - lazy: () => import("../../routes/promotions/promotion-create"), - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/promotions/promotion-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import("../../routes/promotions/promotion-edit-details"), - }, - { - path: "add-to-campaign", - lazy: () => - import("../../routes/promotions/promotion-add-campaign"), - }, - { - path: ":ruleType/edit", - lazy: () => - import("../../routes/promotions/common/edit-rules"), - }, - ], - }, - ], - }, - { - path: "/campaigns", - errorElement: , - handle: { - breadcrumb: () => t("campaigns.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/campaigns/campaign-list"), - children: [], - }, - { - path: "create", - lazy: () => import("../../routes/campaigns/campaign-create"), - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/campaigns/campaign-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/campaigns/campaign-edit"), - }, - { - path: "configuration", - lazy: () => - import("../../routes/campaigns/campaign-configuration"), - }, - { - path: "edit-budget", - lazy: () => - import("../../routes/campaigns/campaign-budget-edit"), - }, - { - path: "add-promotions", - lazy: () => - import("../../routes/campaigns/add-campaign-promotions"), - }, - ], - }, - ], - }, - { - path: "/collections", - errorElement: , - handle: { - breadcrumb: () => t("collections.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/collections/collection-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/collections/collection-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/collections/collection-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import("../../routes/collections/collection-edit"), - }, - { - path: "products", - lazy: () => - import( - "../../routes/collections/collection-add-products" - ), - }, - { - path: "metadata/edit", - lazy: () => - import("../../routes/collections/collection-metadata"), - }, - ], - }, - ], - }, - { - path: "/price-lists", - errorElement: , - handle: { - breadcrumb: () => t("priceLists.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/price-lists/price-list-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/price-lists/price-list-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/price-lists/price-list-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import("../../routes/price-lists/price-list-edit"), - }, - { - path: "configuration", - lazy: () => - import( - "../../routes/price-lists/price-list-configuration" - ), - }, - { - path: "products/add", - lazy: () => - import("../../routes/price-lists/price-list-prices-add"), - }, - { - path: "products/edit", - lazy: () => - import("../../routes/price-lists/price-list-prices-edit"), - }, - ], - }, - ], - }, - { - path: "/customers", - errorElement: , - handle: { - breadcrumb: () => t("customers.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/customers/customer-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/customers/customer-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/customers/customer-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/customers/customer-edit"), - }, - { - path: "add-customer-groups", - lazy: () => - import( - "../../routes/customers/customers-add-customer-group" - ), - }, - { - path: ":order_id/transfer", - lazy: () => - import("../../routes/orders/order-request-transfer"), - }, - { - path: "metadata/edit", - lazy: () => - import("../../routes/customers/customer-metadata"), - }, - ], - }, - ], - }, - { - path: "/customer-groups", - errorElement: , - handle: { - breadcrumb: () => t("customerGroups.domain"), - }, - children: [ - { - path: "", - lazy: () => - import("../../routes/customer-groups/customer-group-list"), - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/customer-groups/customer-group-create" - ), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/customer-groups/customer-group-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/customer-groups/customer-group-edit" - ), - }, - { - path: "add-customers", - lazy: () => - import( - "../../routes/customer-groups/customer-group-add-customers" - ), - }, - { - path: "metadata/edit", - lazy: () => - import( - "../../routes/customer-groups/customer-group-metadata" - ), - }, - ], - }, - ], - }, - { - path: "/reservations", - errorElement: , - handle: { - breadcrumb: () => t("reservations.domain"), - }, - children: [ - { - path: "", - lazy: () => - import("../../routes/reservations/reservation-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/reservations/reservation-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/reservations/reservation-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/reservations/reservation-detail/components/edit-reservation" - ), - }, - { - path: "metadata/edit", - lazy: () => - import("../../routes/reservations/reservation-metadata"), - }, - ], - }, - ], - }, - { - path: "/inventory", - errorElement: , - handle: { - breadcrumb: () => t("inventory.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/inventory/inventory-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/inventory/inventory-create"), - }, - { - path: "stock", - lazy: () => - import("../../routes/inventory/inventory-stock"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/inventory/inventory-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/inventory/inventory-detail/components/edit-inventory-item" - ), - }, - { - path: "attributes", - lazy: () => - import( - "../../routes/inventory/inventory-detail/components/edit-inventory-item-attributes" - ), - }, - { - path: "metadata/edit", - lazy: () => - import("../../routes/inventory/inventory-metadata"), - }, - { - path: "locations", - lazy: () => - import( - "../../routes/inventory/inventory-detail/components/manage-locations" - ), - }, - { - path: "locations/:location_id", - lazy: () => - import( - "../../routes/inventory/inventory-detail/components/adjust-inventory" - ), - }, - ], - }, - ], - }, - ...RouteExtensions, - ], - }, - ], - }, - { - element: , - errorElement: , - children: [ - { - path: "/settings", - handle: { - breadcrumb: () => t("app.nav.settings.header"), - }, - element: , - children: [ - { - index: true, - errorElement: , - lazy: () => import("../../routes/settings"), - }, - { - path: "profile", - errorElement: , - lazy: () => import("../../routes/profile/profile-detail"), - handle: { - breadcrumb: () => t("profile.domain"), - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/profile/profile-edit"), - }, - ], - }, - { - path: "regions", - errorElement: , - element: , - handle: { - breadcrumb: () => t("regions.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/regions/region-list"), - children: [ - { - path: "create", - lazy: () => import("../../routes/regions/region-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/regions/region-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/regions/region-edit"), - }, - { - path: "countries/add", - lazy: () => - import("../../routes/regions/region-add-countries"), - }, - { - path: "metadata/edit", - lazy: () => import("../../routes/regions/region-metadata"), - }, - ], - }, - ], - }, - { - path: "store", - errorElement: , - lazy: () => import("../../routes/store/store-detail"), - handle: { - breadcrumb: () => t("store.domain"), - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/store/store-edit"), - }, - { - path: "currencies", - lazy: () => import("../../routes/store/store-add-currencies"), - }, - { - path: "metadata/edit", - lazy: () => import("../../routes/store/store-metadata"), - }, - ], - }, - { - path: "users", - errorElement: , - element: , - handle: { - breadcrumb: () => t("users.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/users/user-list"), - children: [ - { - path: "invite", - lazy: () => import("../../routes/users/user-invite"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/users/user-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/users/user-edit"), - }, - { - path: "metadata/edit", - lazy: () => import("../../routes/users/user-metadata"), - }, - ], - }, - ], - }, - { - path: "sales-channels", - errorElement: , - element: , - handle: { - breadcrumb: () => t("salesChannels.domain"), - }, - children: [ - { - path: "", - lazy: () => - import("../../routes/sales-channels/sales-channel-list"), - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/sales-channels/sales-channel-create" - ), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/sales-channels/sales-channel-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import("../../routes/sales-channels/sales-channel-edit"), - }, - { - path: "add-products", - lazy: () => - import( - "../../routes/sales-channels/sales-channel-add-products" - ), - }, - { - path: "metadata/edit", - lazy: () => - import( - "../../routes/sales-channels/sales-channel-metadata" - ), - }, - ], - }, - ], - }, - { - path: "locations", - errorElement: , - element: , - handle: { - breadcrumb: () => t("locations.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/locations/location-list"), - }, - { - path: "create", - lazy: () => import("../../routes/locations/location-create"), - }, - { - path: "shipping-profiles", - element: , - handle: { - breadcrumb: () => t("shippingProfile.domain"), - }, - children: [ - { - path: "", - lazy: () => - import( - "../../routes/shipping-profiles/shipping-profiles-list" - ), - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/shipping-profiles/shipping-profile-create" - ), - }, - ], - }, - { - path: ":shipping_profile_id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/shipping-profiles/shipping-profile-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - // eslint-disable-next-line max-len - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "metadata/edit", - lazy: () => - import( - "../../routes/shipping-profiles/shipping-profile-metadata" - ), - }, - ], - }, - ], - }, - { - path: ":location_id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/locations/location-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => import("../../routes/locations/location-edit"), - }, - { - path: "sales-channels", - lazy: () => - import("../../routes/locations/location-sales-channels"), - }, - { - path: "fulfillment-providers", - lazy: () => - import( - "../../routes/locations/location-fulfillment-providers" - ), - }, - { - path: "fulfillment-set/:fset_id", - children: [ - { - path: "service-zones/create", - lazy: () => - import( - "../../routes/locations/location-service-zone-create" - ), - }, - { - path: "service-zone/:zone_id", - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/locations/location-service-zone-edit" - ), - }, - { - path: "areas", - lazy: () => - import( - "../../routes/locations/location-service-zone-manage-areas" - ), - }, - { - path: "shipping-option", - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/locations/location-service-zone-shipping-option-create" - ), - }, - { - path: ":so_id", - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/locations/location-service-zone-shipping-option-edit" - ), - }, - { - path: "pricing", - lazy: () => - import( - "../../routes/locations/location-service-zone-shipping-option-pricing" - ), - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - path: "product-tags", - errorElement: , - element: , - handle: { - breadcrumb: () => t("productTags.domain"), - }, - children: [ - { - path: "", - lazy: () => - import("../../routes/product-tags/product-tag-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/product-tags/product-tag-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/product-tags/product-tag-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import("../../routes/product-tags/product-tag-edit"), - }, - ], - }, - ], - }, - { - path: "workflows", - errorElement: , - element: , - handle: { - breadcrumb: () => t("workflowExecutions.domain"), - }, - children: [ - { - path: "", - lazy: () => - import( - "../../routes/workflow-executions/workflow-execution-list" - ), - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/workflow-executions/workflow-execution-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - }, - ], - }, - { - path: "product-types", - errorElement: , - element: , - handle: { - breadcrumb: () => t("productTypes.domain"), - }, - children: [ - { - path: "", - lazy: () => - import("../../routes/product-types/product-type-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/product-types/product-type-create"), - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/product-types/product-type-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import("../../routes/product-types/product-type-edit"), - }, - ], - }, - ], - }, - { - path: "publishable-api-keys", - element: , - handle: { - breadcrumb: () => t("apiKeyManagement.domain.publishable"), - }, - children: [ - { - path: "", - element: , - children: [ - { - path: "", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-list" - ), - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-create" - ), - }, - ], - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/api-key-management/api-key-management-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-edit" - ), - }, - { - path: "sales-channels", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-sales-channels" - ), - }, - ], - }, - ], - }, - { - path: "secret-api-keys", - element: , - handle: { - breadcrumb: () => t("apiKeyManagement.domain.secret"), - }, - children: [ - { - path: "", - element: , - children: [ - { - path: "", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-list" - ), - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-create" - ), - }, - ], - }, - ], - }, - { - path: ":id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/api-key-management/api-key-management-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/api-key-management/api-key-management-edit" - ), - }, - ], - }, - ], - }, - { - path: "tax-regions", - element: , - handle: { - breadcrumb: () => t("taxRegions.domain"), - }, - children: [ - { - path: "", - lazy: () => import("../../routes/tax-regions/tax-region-list"), - children: [ - { - path: "create", - lazy: () => - import("../../routes/tax-regions/tax-region-create"), - }, - ], - }, - { - path: ":id", - Component: Outlet, - loader: taxRegionLoader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - children: [ - { - path: "", - lazy: async () => { - const { Component } = await import( - "../../routes/tax-regions/tax-region-detail" - ) - - return { - Component, - } - }, - children: [ - { - path: "provinces/create", - lazy: () => - import( - "../../routes/tax-regions/tax-region-province-create" - ), - }, - { - path: "overrides/create", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-override-create" - ), - }, - { - path: "overrides/:tax_rate_id/edit", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-override-edit" - ), - }, - { - path: "tax-rates/create", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-rate-create" - ), - }, - { - path: "tax-rates/:tax_rate_id/edit", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-rate-edit" - ), - }, - ], - }, - { - path: "provinces/:province_id", - lazy: async () => { - const { Component, Breadcrumb, loader } = await import( - "../../routes/tax-regions/tax-region-province-detail" - ) - - return { - Component, - loader, - handle: { - breadcrumb: ( - match: UIMatch - ) => , - }, - } - }, - children: [ - { - path: "tax-rates/create", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-rate-create" - ), - }, - { - path: "tax-rates/:tax_rate_id/edit", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-rate-edit" - ), - }, - { - path: "overrides/create", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-override-create" - ), - }, - { - path: "overrides/:tax_rate_id/edit", - lazy: () => - import( - "../../routes/tax-regions/tax-region-tax-override-edit" - ), - }, - ], - }, - ], - }, - ], - }, - { - path: "return-reasons", - element: , - handle: { - breadcrumb: () => t("returnReasons.domain"), - }, - children: [ - { - path: "", - lazy: () => - import("../../routes/return-reasons/return-reason-list"), - children: [ - { - path: "create", - lazy: () => - import( - "../../routes/return-reasons/return-reason-create" - ), - }, - - { - path: ":id", - children: [ - { - path: "edit", - lazy: () => - import( - "../../routes/return-reasons/return-reason-edit" - ), - }, - ], - }, - ], - }, - ], - }, - ...SettingsExtensions, - ], - }, - ], - }, - { - element: , - children: [ - { - errorElement: , - children: [ - { - path: "/login", - lazy: () => import("../../routes/login"), - }, - { - path: "/reset-password", - lazy: () => import("../../routes/reset-password"), - }, - { - path: "/invite", - lazy: () => import("../../routes/invite"), - }, - { - path: "*", - lazy: () => import("../../routes/no-match"), - }, - ], - }, - ], - }, -] diff --git a/packages/admin/dashboard/src/providers/router-provider/router-provider.tsx b/packages/admin/dashboard/src/providers/router-provider/router-provider.tsx deleted file mode 100644 index 87b6041774..0000000000 --- a/packages/admin/dashboard/src/providers/router-provider/router-provider.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { - RouterProvider as Provider, - createBrowserRouter, -} from "react-router-dom" - -import { RouteMap } from "./route-map" - -const router = createBrowserRouter(RouteMap, { - basename: __BASE__ || "/", -}) - -export const RouterProvider = () => { - return -} diff --git a/packages/admin/dashboard/src/providers/router-provider/settings-extensions.tsx b/packages/admin/dashboard/src/providers/router-provider/settings-extensions.tsx deleted file mode 100644 index 0949739307..0000000000 --- a/packages/admin/dashboard/src/providers/router-provider/settings-extensions.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import routeModule from "virtual:medusa/routes" -import { - createRouteMap, - getRouteExtensions, -} from "../../extensions/routes/utils" - -const routes = getRouteExtensions(routeModule, "settings") - -/** - * Settings Route extensions. - */ -export const SettingsExtensions = createRouteMap(routes, "/settings") diff --git a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/api-key-management-detail.tsx b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/api-key-management-detail.tsx index 2735520caf..993c23e7e6 100644 --- a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/api-key-management-detail.tsx +++ b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-detail/api-key-management-detail.tsx @@ -2,8 +2,8 @@ import { useLoaderData, useParams } from "react-router-dom" import { SingleColumnPageSkeleton } from "../../../components/common/skeleton" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" import { useApiKey } from "../../../hooks/api/api-keys" +import { useExtension } from "../../../providers/extension-provider" import { ApiKeyType } from "../common/constants" import { ApiKeyGeneralSection } from "./components/api-key-general-section" import { ApiKeySalesChannelSection } from "./components/api-key-sales-channel-section" @@ -15,7 +15,7 @@ export const ApiKeyManagementDetail = () => { > const { id } = useParams() - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const { api_key, isLoading, isError, error } = useApiKey(id!, { initialData: initialData, diff --git a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-list/api-key-management-list.tsx b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-list/api-key-management-list.tsx index b6b2cf000d..0c07b26437 100644 --- a/packages/admin/dashboard/src/routes/api-key-management/api-key-management-list/api-key-management-list.tsx +++ b/packages/admin/dashboard/src/routes/api-key-management/api-key-management-list/api-key-management-list.tsx @@ -3,11 +3,11 @@ import { getApiKeyTypeFromPathname } from "../common/utils" import { ApiKeyManagementListTable } from "./components/api-key-management-list-table" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" export const ApiKeyManagementList = () => { const { pathname } = useLocation() - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const keyType = getApiKeyTypeFromPathname(pathname) diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx index a802e4e998..372d45d6f8 100644 --- a/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-detail/campaign-detail.tsx @@ -9,7 +9,7 @@ import { campaignLoader } from "./loader" import { TwoColumnPageSkeleton } from "../../../components/common/skeleton" import { TwoColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { CampaignConfigurationSection } from "./components/campaign-configuration-section" import { CAMPAIGN_DETAIL_FIELDS } from "./constants" @@ -25,7 +25,7 @@ export const CampaignDetail = () => { { initialData } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !campaign) { return ( diff --git a/packages/admin/dashboard/src/routes/campaigns/campaign-list/campaign-list.tsx b/packages/admin/dashboard/src/routes/campaigns/campaign-list/campaign-list.tsx index 7c01e276ad..0cdeab700d 100644 --- a/packages/admin/dashboard/src/routes/campaigns/campaign-list/campaign-list.tsx +++ b/packages/admin/dashboard/src/routes/campaigns/campaign-list/campaign-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { CampaignListTable } from "./components/campaign-list-table" export const CampaignList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { const { id } = useParams() @@ -16,7 +16,7 @@ export const CategoryDetail = () => { ReturnType > - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const { product_category, isLoading, isError, error } = useProductCategory( id!, diff --git a/packages/admin/dashboard/src/routes/categories/category-list/category-list.tsx b/packages/admin/dashboard/src/routes/categories/category-list/category-list.tsx index 0f77bd2578..8d06b910fc 100644 --- a/packages/admin/dashboard/src/routes/categories/category-list/category-list.tsx +++ b/packages/admin/dashboard/src/routes/categories/category-list/category-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { CategoryListTable } from "./components/category-list-table" export const CategoryList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { initialData, }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !collection) { return diff --git a/packages/admin/dashboard/src/routes/collections/collection-list/collection-list.tsx b/packages/admin/dashboard/src/routes/collections/collection-list/collection-list.tsx index 29b514382d..43054e261c 100644 --- a/packages/admin/dashboard/src/routes/collections/collection-list/collection-list.tsx +++ b/packages/admin/dashboard/src/routes/collections/collection-list/collection-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { CollectionListTable } from "./components/collection-list-table" export const CollectionList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { @@ -24,7 +24,7 @@ export const CustomerGroupDetail = () => { { initialData } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !customer_group) { return diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx b/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx index ff1ac01aac..ddeef19896 100644 --- a/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx +++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx @@ -1,10 +1,10 @@ import { PencilSquare, Trash } from "@medusajs/icons" import { HttpTypes } from "@medusajs/types" import { - Container, - createDataTableColumnHelper, - toast, - usePrompt, + Container, + createDataTableColumnHelper, + toast, + usePrompt, } from "@medusajs/ui" import { keepPreviousData } from "@tanstack/react-query" import { useCallback, useMemo } from "react" @@ -14,19 +14,19 @@ import { useNavigate } from "react-router-dom" import { DataTable } from "../../../../../components/data-table" import { useDataTableDateFilters } from "../../../../../components/data-table/helpers/general/use-data-table-date-filters" import { SingleColumnPage } from "../../../../../components/layout/pages" -import { useDashboardExtension } from "../../../../../extensions" import { - useCustomerGroups, - useDeleteCustomerGroupLazy, + useCustomerGroups, + useDeleteCustomerGroupLazy, } from "../../../../../hooks/api" import { useDate } from "../../../../../hooks/use-date" import { useQueryParams } from "../../../../../hooks/use-query-params" +import { useExtension } from "../../../../../providers/extension-provider" const PAGE_SIZE = 10 export const CustomerGroupListTable = () => { const { t } = useTranslation() - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const { q, order, offset, created_at, updated_at } = useQueryParams([ "q", diff --git a/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/customer-group-list.tsx b/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/customer-group-list.tsx index 7230f44218..1bd613e63c 100644 --- a/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/customer-group-list.tsx +++ b/packages/admin/dashboard/src/routes/customer-groups/customer-group-list/customer-group-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { CustomerGroupListTable } from "./components/customer-group-list-table" export const CustomerGroupsList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { initialData, }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !customer) { return diff --git a/packages/admin/dashboard/src/routes/customers/customer-list/customer-list.tsx b/packages/admin/dashboard/src/routes/customers/customer-list/customer-list.tsx index 69726a4f28..89324be89f 100644 --- a/packages/admin/dashboard/src/routes/customers/customer-list/customer-list.tsx +++ b/packages/admin/dashboard/src/routes/customers/customer-list/customer-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { CustomerListTable } from "./components/customer-list-table" export const CustomersList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { @@ -35,7 +35,7 @@ export const InventoryDetail = () => { } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !inventory_item) { return ( diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-list/inventory-list.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-list/inventory-list.tsx index a26036f8dc..52d9630bb4 100644 --- a/packages/admin/dashboard/src/routes/inventory/inventory-list/inventory-list.tsx +++ b/packages/admin/dashboard/src/routes/inventory/inventory-list/inventory-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { InventoryListTable } from "./components/inventory-list-table" export const InventoryItemListTable = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { { initialData } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !location) { return ( diff --git a/packages/admin/dashboard/src/routes/locations/location-list/location-list.tsx b/packages/admin/dashboard/src/routes/locations/location-list/location-list.tsx index 1f99f9241b..11557f1351 100644 --- a/packages/admin/dashboard/src/routes/locations/location-list/location-list.tsx +++ b/packages/admin/dashboard/src/routes/locations/location-list/location-list.tsx @@ -1,19 +1,17 @@ -import { ShoppingBag, TriangleRightMini } from "@medusajs/icons" -import { Container, Heading, Text } from "@medusajs/ui" +import { ShoppingBag } from "@medusajs/icons" +import { Container, Heading } from "@medusajs/ui" import { useTranslation } from "react-i18next" -import { Link, useLoaderData } from "react-router-dom" +import { useLoaderData } from "react-router-dom" import { useStockLocations } from "../../../hooks/api/stock-locations" import LocationListItem from "./components/location-list-item/location-list-item" import { LOCATION_LIST_FIELDS } from "./constants" import { shippingListLoader } from "./loader" -import { ReactNode } from "react" -import { IconAvatar } from "../../../components/common/icon-avatar" -import { TwoColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" -import { LocationListHeader } from "./components/location-list-header" import { SidebarLink } from "../../../components/common/sidebar-link/sidebar-link" +import { TwoColumnPage } from "../../../components/layout/pages" +import { useExtension } from "../../../providers/extension-provider" +import { LocationListHeader } from "./components/location-list-header" export function LocationList() { const initialData = useLoaderData() as Awaited< @@ -31,7 +29,7 @@ export function LocationList() { { initialData } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isError) { throw error diff --git a/packages/admin/dashboard/src/routes/login/login.tsx b/packages/admin/dashboard/src/routes/login/login.tsx index 497ed117d2..482b8d404b 100644 --- a/packages/admin/dashboard/src/routes/login/login.tsx +++ b/packages/admin/dashboard/src/routes/login/login.tsx @@ -7,9 +7,9 @@ import * as z from "zod" import { Form } from "../../components/common/form" import AvatarBox from "../../components/common/logo-box/avatar-box" -import { useDashboardExtension } from "../../extensions" import { useSignInWithEmailPass } from "../../hooks/api" import { isFetchError } from "../../lib/is-fetch-error" +import { useExtension } from "../../providers/extension-provider" const LoginSchema = z.object({ email: z.string().email(), @@ -20,7 +20,7 @@ export const Login = () => { const { t } = useTranslation() const location = useLocation() const navigate = useNavigate() - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const from = location.state?.from?.pathname || "/orders" diff --git a/packages/admin/dashboard/src/routes/orders/order-detail/order-detail.tsx b/packages/admin/dashboard/src/routes/orders/order-detail/order-detail.tsx index de80b0be3b..77e01cdb9b 100644 --- a/packages/admin/dashboard/src/routes/orders/order-detail/order-detail.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-detail/order-detail.tsx @@ -2,8 +2,8 @@ import { useLoaderData, useParams } from "react-router-dom" import { TwoColumnPageSkeleton } from "../../../components/common/skeleton" import { TwoColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" import { useOrder, useOrderPreview } from "../../../hooks/api/orders" +import { useExtension } from "../../../providers/extension-provider" import { ActiveOrderClaimSection } from "./components/active-order-claim-section" import { ActiveOrderExchangeSection } from "./components/active-order-exchange-section" import { ActiveOrderReturnSection } from "./components/active-order-return-section" @@ -21,7 +21,7 @@ export const OrderDetail = () => { const initialData = useLoaderData() as Awaited> const { id } = useParams() - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const { order, isLoading, isError, error } = useOrder( id!, diff --git a/packages/admin/dashboard/src/routes/orders/order-list/order-list.tsx b/packages/admin/dashboard/src/routes/orders/order-list/order-list.tsx index 96acaa61c0..af8b8c2b75 100644 --- a/packages/admin/dashboard/src/routes/orders/order-list/order-list.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-list/order-list.tsx @@ -1,10 +1,10 @@ import { OrderListTable } from "./components/order-list-table" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" export const OrderList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { const { id } = useParams() const { price_list, isLoading, isError, error } = usePriceList(id!) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !price_list) { return ( diff --git a/packages/admin/dashboard/src/routes/price-lists/price-list-list/price-list-list.tsx b/packages/admin/dashboard/src/routes/price-lists/price-list-list/price-list-list.tsx index 4d74ddef60..b9e8a947e0 100644 --- a/packages/admin/dashboard/src/routes/price-lists/price-list-list/price-list-list.tsx +++ b/packages/admin/dashboard/src/routes/price-lists/price-list-list/price-list-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { PriceListListTable } from "./components/price-list-list-table" export const PriceListList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { ReturnType > - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const { product_tag, isPending, isError, error } = useProductTag( id!, diff --git a/packages/admin/dashboard/src/routes/product-tags/product-tag-list/product-tag-list.tsx b/packages/admin/dashboard/src/routes/product-tags/product-tag-list/product-tag-list.tsx index a612a12498..cb14d031c2 100644 --- a/packages/admin/dashboard/src/routes/product-tags/product-tag-list/product-tag-list.tsx +++ b/packages/admin/dashboard/src/routes/product-tags/product-tag-list/product-tag-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { ProductTagListTable } from "./components/product-tag-list-table" export const ProductTagList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isPending || !product_type) { return diff --git a/packages/admin/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx b/packages/admin/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx index 837482e242..7bca2c2b55 100644 --- a/packages/admin/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx +++ b/packages/admin/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { ProductTypeListTable } from "./components/product-type-list-table" export const ProductTypeList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !variant) { return ( diff --git a/packages/admin/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx b/packages/admin/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx index 9eec54aed8..87a4d4b36c 100644 --- a/packages/admin/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx +++ b/packages/admin/dashboard/src/routes/products/product-attributes/components/product-attributes-form/product-attributes-form.tsx @@ -8,10 +8,10 @@ import { RouteDrawer, useRouteModal } from "../../../../../components/modals" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { FormExtensionZone, - useDashboardExtension, useExtendableForm, -} from "../../../../../extensions" +} from "../../../../../dashboard-app" import { useUpdateProduct } from "../../../../../hooks/api/products" +import { useExtension } from "../../../../../providers/extension-provider" type ProductAttributesFormProps = { product: HttpTypes.AdminProduct @@ -43,7 +43,7 @@ export const ProductAttributesForm = ({ }: ProductAttributesFormProps) => { const { t } = useTranslation() const { handleSuccess } = useRouteModal() - const { getFormConfigs, getFormFields } = useDashboardExtension() + const { getFormConfigs, getFormFields } = useExtension() const configs = getFormConfigs("product", "attributes") const fields = getFormFields("product", "attributes") diff --git a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-details-form/product-create-details-form.tsx b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-details-form/product-create-details-form.tsx index f19678c170..7e119b85ce 100644 --- a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-details-form/product-create-details-form.tsx +++ b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-details-form/product-create-details-form.tsx @@ -2,10 +2,8 @@ import { Divider, Heading } from "@medusajs/ui" import { UseFormReturn } from "react-hook-form" import { useTranslation } from "react-i18next" -import { - FormExtensionZone, - useDashboardExtension, -} from "../../../../../extensions" +import { FormExtensionZone } from "../../../../../dashboard-app" +import { useExtension } from "../../../../../providers/extension-provider" import { ProductCreateSchemaType } from "../../types" import { ProductCreateGeneralSection } from "./components/product-create-details-general-section" import { ProductCreateMediaSection } from "./components/product-create-details-media-section" @@ -16,7 +14,7 @@ type ProductAttributesProps = { } export const ProductCreateDetailsForm = ({ form }: ProductAttributesProps) => { - const { getFormFields } = useDashboardExtension() + const { getFormFields } = useExtension() const fields = getFormFields("product", "create", "general") return ( diff --git a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx index f4ba63318f..7ec650dffb 100644 --- a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx +++ b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-form/product-create-form.tsx @@ -8,12 +8,10 @@ import { useRouteModal, } from "../../../../../components/modals" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" -import { - useDashboardExtension, - useExtendableForm, -} from "../../../../../extensions" +import { useExtendableForm } from "../../../../../dashboard-app/forms/hooks" import { useCreateProduct } from "../../../../../hooks/api/products" import { sdk } from "../../../../../lib/client" +import { useExtension } from "../../../../../providers/extension-provider" import { PRODUCT_CREATE_FORM_DEFAULTS, ProductCreateSchema, @@ -58,7 +56,7 @@ export const ProductCreateForm = ({ const { t } = useTranslation() const { handleSuccess } = useRouteModal() - const { getFormConfigs } = useDashboardExtension() + const { getFormConfigs } = useExtension() const configs = getFormConfigs("product", "create") const form = useExtendableForm({ diff --git a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-organize-form/product-create-organize-form.tsx b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-organize-form/product-create-organize-form.tsx index 37ef9882ba..377da3d74f 100644 --- a/packages/admin/dashboard/src/routes/products/product-create/components/product-create-organize-form/product-create-organize-form.tsx +++ b/packages/admin/dashboard/src/routes/products/product-create/components/product-create-organize-form/product-create-organize-form.tsx @@ -1,10 +1,8 @@ import { UseFormReturn } from "react-hook-form" import { StackedFocusModal } from "../../../../../components/modals" -import { - FormExtensionZone, - useDashboardExtension, -} from "../../../../../extensions" +import { FormExtensionZone } from "../../../../../dashboard-app" +import { useExtension } from "../../../../../providers/extension-provider" import { ProductCreateSchemaType } from "../../types" import { ProductCreateOrganizationSection } from "./components/product-create-organize-section" import { ProductCreateSalesChannelStackedModal } from "./components/product-create-sales-channel-stacked-modal" @@ -15,7 +13,7 @@ type ProductAttributesProps = { } export const ProductCreateOrganizeForm = ({ form }: ProductAttributesProps) => { - const { getFormFields } = useDashboardExtension() + const { getFormFields } = useExtension() const fields = getFormFields("product", "create", "organize") return ( diff --git a/packages/admin/dashboard/src/routes/products/product-detail/components/product-attribute-section/product-attribute-section.tsx b/packages/admin/dashboard/src/routes/products/product-detail/components/product-attribute-section/product-attribute-section.tsx index 66b85ddb4c..98ff3d00eb 100644 --- a/packages/admin/dashboard/src/routes/products/product-detail/components/product-attribute-section/product-attribute-section.tsx +++ b/packages/admin/dashboard/src/routes/products/product-detail/components/product-attribute-section/product-attribute-section.tsx @@ -4,8 +4,8 @@ import { Container, Heading } from "@medusajs/ui" import { useTranslation } from "react-i18next" import { ActionMenu } from "../../../../../components/common/action-menu" import { SectionRow } from "../../../../../components/common/section" -import { useDashboardExtension } from "../../../../../extensions" import { getFormattedCountry } from "../../../../../lib/addresses" +import { useExtension } from "../../../../../providers/extension-provider" type ProductAttributeSectionProps = { product: HttpTypes.AdminProduct @@ -15,7 +15,7 @@ export const ProductAttributeSection = ({ product, }: ProductAttributeSectionProps) => { const { t } = useTranslation() - const { getDisplays } = useDashboardExtension() + const { getDisplays } = useExtension() return ( diff --git a/packages/admin/dashboard/src/routes/products/product-detail/components/product-general-section/product-general-section.tsx b/packages/admin/dashboard/src/routes/products/product-detail/components/product-general-section/product-general-section.tsx index e95e345a08..f813836794 100644 --- a/packages/admin/dashboard/src/routes/products/product-detail/components/product-general-section/product-general-section.tsx +++ b/packages/admin/dashboard/src/routes/products/product-detail/components/product-general-section/product-general-section.tsx @@ -6,8 +6,8 @@ import { useNavigate } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" import { SectionRow } from "../../../../../components/common/section" -import { useDashboardExtension } from "../../../../../extensions" import { useDeleteProduct } from "../../../../../hooks/api/products" +import { useExtension } from "../../../../../providers/extension-provider" const productStatusColor = (status: string) => { switch (status) { @@ -34,7 +34,7 @@ export const ProductGeneralSection = ({ const { t } = useTranslation() const prompt = usePrompt() const navigate = useNavigate() - const { getDisplays } = useDashboardExtension() + const { getDisplays } = useExtension() const displays = getDisplays("product", "general") diff --git a/packages/admin/dashboard/src/routes/products/product-detail/components/product-organization-section/product-organization-section.tsx b/packages/admin/dashboard/src/routes/products/product-detail/components/product-organization-section/product-organization-section.tsx index c8f722513d..14415318ff 100644 --- a/packages/admin/dashboard/src/routes/products/product-detail/components/product-organization-section/product-organization-section.tsx +++ b/packages/admin/dashboard/src/routes/products/product-detail/components/product-organization-section/product-organization-section.tsx @@ -5,7 +5,7 @@ import { useTranslation } from "react-i18next" import { Link } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" import { SectionRow } from "../../../../../components/common/section" -import { useDashboardExtension } from "../../../../../extensions" +import { useExtension } from "../../../../../providers/extension-provider" type ProductOrganizationSectionProps = { product: HttpTypes.AdminProduct @@ -15,7 +15,7 @@ export const ProductOrganizationSection = ({ product, }: ProductOrganizationSectionProps) => { const { t } = useTranslation() - const { getDisplays } = useDashboardExtension() + const { getDisplays } = useExtension() return ( diff --git a/packages/admin/dashboard/src/routes/products/product-detail/constants.ts b/packages/admin/dashboard/src/routes/products/product-detail/constants.ts index fcc4006988..e5f98171e8 100644 --- a/packages/admin/dashboard/src/routes/products/product-detail/constants.ts +++ b/packages/admin/dashboard/src/routes/products/product-detail/constants.ts @@ -1,4 +1,4 @@ -import { getLinkedFields } from "../../../extensions" +import { getLinkedFields } from "../../../dashboard-app" export const PRODUCT_DETAIL_FIELDS = getLinkedFields( "product", diff --git a/packages/admin/dashboard/src/routes/products/product-detail/product-detail.tsx b/packages/admin/dashboard/src/routes/products/product-detail/product-detail.tsx index 78ece96f60..c9a9a62915 100644 --- a/packages/admin/dashboard/src/routes/products/product-detail/product-detail.tsx +++ b/packages/admin/dashboard/src/routes/products/product-detail/product-detail.tsx @@ -13,7 +13,7 @@ import { ProductVariantSection } from "./components/product-variant-section" import { PRODUCT_DETAIL_FIELDS } from "./constants" import { productLoader } from "./loader" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { ProductShippingProfileSection } from "./components/product-shipping-profile-section" export const ProductDetail = () => { @@ -30,7 +30,7 @@ export const ProductDetail = () => { } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() const after = getWidgets("product.details.after") const before = getWidgets("product.details.before") diff --git a/packages/admin/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx b/packages/admin/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx index 819d9c02a8..5020dd5c79 100644 --- a/packages/admin/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx +++ b/packages/admin/dashboard/src/routes/products/product-edit/components/edit-product-form/edit-product-form.tsx @@ -6,15 +6,13 @@ import { HttpTypes } from "@medusajs/types" import { Form } from "../../../../../components/common/form" import { SwitchBox } from "../../../../../components/common/switch-box" import { RouteDrawer, useRouteModal } from "../../../../../components/modals" -import { useExtendableForm } from "../../../../../extensions/forms/hooks" +import { useExtendableForm } from "../../../../../dashboard-app/forms/hooks" import { useUpdateProduct } from "../../../../../hooks/api/products" import { transformNullableFormData } from "../../../../../lib/form-helpers" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" -import { - FormExtensionZone, - useDashboardExtension, -} from "../../../../../extensions" +import { FormExtensionZone } from "../../../../../dashboard-app" +import { useExtension } from "../../../../../providers/extension-provider" type EditProductFormProps = { product: HttpTypes.AdminProduct @@ -34,7 +32,7 @@ export const EditProductForm = ({ product }: EditProductFormProps) => { const { t } = useTranslation() const { handleSuccess } = useRouteModal() - const { getFormFields, getFormConfigs } = useDashboardExtension() + const { getFormFields, getFormConfigs } = useExtension() const fields = getFormFields("product", "edit") const configs = getFormConfigs("product", "edit") diff --git a/packages/admin/dashboard/src/routes/products/product-list/product-list.tsx b/packages/admin/dashboard/src/routes/products/product-list/product-list.tsx index c22841f97e..62c447c660 100644 --- a/packages/admin/dashboard/src/routes/products/product-list/product-list.tsx +++ b/packages/admin/dashboard/src/routes/products/product-list/product-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { ProductListTable } from "./components/product-list-table" export const ProductList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { const { t } = useTranslation() const { handleSuccess } = useRouteModal() - const { getFormConfigs, getFormFields } = useDashboardExtension() + const { getFormConfigs, getFormFields } = useExtension() const configs = getFormConfigs("product", "organize") const fields = getFormFields("product", "organize") diff --git a/packages/admin/dashboard/src/routes/profile/profile-detail/profile-detail.tsx b/packages/admin/dashboard/src/routes/profile/profile-detail/profile-detail.tsx index a36aee5f5b..76e0f11301 100644 --- a/packages/admin/dashboard/src/routes/profile/profile-detail/profile-detail.tsx +++ b/packages/admin/dashboard/src/routes/profile/profile-detail/profile-detail.tsx @@ -3,11 +3,11 @@ import { ProfileGeneralSection } from "./components/profile-general-section" import { SingleColumnPageSkeleton } from "../../../components/common/skeleton" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" export const ProfileDetail = () => { const { user, isPending: isLoading, isError, error } = useMe() - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !user) { return diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx index 765952b9a8..a5fefa61c7 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-detail/promotion-detail.tsx @@ -2,8 +2,8 @@ import { useLoaderData, useParams } from "react-router-dom" import { TwoColumnPageSkeleton } from "../../../components/common/skeleton" import { TwoColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" import { usePromotion, usePromotionRules } from "../../../hooks/api/promotions" +import { useExtension } from "../../../providers/extension-provider" import { CampaignSection } from "./components/campaign-section" import { PromotionConditionsSection } from "./components/promotion-conditions-section" import { PromotionGeneralSection } from "./components/promotion-general-section" @@ -26,7 +26,7 @@ export const PromotionDetail = () => { const { rules: targetRules } = usePromotionRules(id!, "target-rules", query) const { rules: buyRules } = usePromotionRules(id!, "buy-rules", query) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !promotion) { return ( diff --git a/packages/admin/dashboard/src/routes/promotions/promotion-list/promotions-list.tsx b/packages/admin/dashboard/src/routes/promotions/promotion-list/promotions-list.tsx index 1994f7e260..793b8b4cb4 100644 --- a/packages/admin/dashboard/src/routes/promotions/promotion-list/promotions-list.tsx +++ b/packages/admin/dashboard/src/routes/promotions/promotion-list/promotions-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { PromotionListTable } from "./components/promotion-list-table" export const PromotionsList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { @@ -43,7 +43,7 @@ export const RegionDetail = () => { { enabled: !!region } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || isLoadingPreferences || !region) { return diff --git a/packages/admin/dashboard/src/routes/regions/region-list/region-list.tsx b/packages/admin/dashboard/src/routes/regions/region-list/region-list.tsx index 1a7eaea67d..6d6f81217f 100644 --- a/packages/admin/dashboard/src/routes/regions/region-list/region-list.tsx +++ b/packages/admin/dashboard/src/routes/regions/region-list/region-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { RegionListTable } from "./components/region-list-table" export const RegionList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { const { id } = useParams() @@ -31,7 +31,7 @@ export const ReservationDetail = () => { { enabled: !!reservation?.inventory_item?.id! } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !reservation) { return ( diff --git a/packages/admin/dashboard/src/routes/reservations/reservation-list/reservation-list.tsx b/packages/admin/dashboard/src/routes/reservations/reservation-list/reservation-list.tsx index 6de0532af8..b619cbfb8a 100644 --- a/packages/admin/dashboard/src/routes/reservations/reservation-list/reservation-list.tsx +++ b/packages/admin/dashboard/src/routes/reservations/reservation-list/reservation-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { ReservationListTable } from "./components/reservation-list-table" export const ReservationList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { initialData, }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !sales_channel) { return diff --git a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-list/sales-channel-list.tsx b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-list/sales-channel-list.tsx index 4378114428..8c7dc58a6e 100644 --- a/packages/admin/dashboard/src/routes/sales-channels/sales-channel-list/sales-channel-list.tsx +++ b/packages/admin/dashboard/src/routes/sales-channels/sales-channel-list/sales-channel-list.tsx @@ -1,10 +1,10 @@ import { SalesChannelListTable } from "./components/sales-channel-list-table" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" export const SalesChannelList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { @@ -21,7 +21,7 @@ export const ShippingProfileDetail = () => { { initialData } ) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !shipping_profile) { return diff --git a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profiles-list/shipping-profile-list.tsx b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profiles-list/shipping-profile-list.tsx index 8fc9edc66d..7beabfc423 100644 --- a/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profiles-list/shipping-profile-list.tsx +++ b/packages/admin/dashboard/src/routes/shipping-profiles/shipping-profiles-list/shipping-profile-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { ShippingProfileListTable } from "./components/shipping-profile-list-table" export const ShippingProfileList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { const initialData = useLoaderData() as Awaited> @@ -16,7 +16,7 @@ export const StoreDetail = () => { initialData, }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isPending || !store) { return diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/tax-region-detail.tsx b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/tax-region-detail.tsx index 327e8b08e3..9809b3cee0 100644 --- a/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/tax-region-detail.tsx +++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-detail/tax-region-detail.tsx @@ -7,7 +7,7 @@ import { TaxRegionProvinceSection } from "./components/tax-region-province-secti import { useState } from "react" import { SingleColumnPageSkeleton } from "../../../components/common/skeleton" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { TaxRegionOverrideSection } from "./components/tax-region-override-section" import { TaxRegionSublevelAlert } from "./components/tax-region-sublevel-alert" import { taxRegionLoader } from "./loader" @@ -27,7 +27,7 @@ export const TaxRegionDetail = () => { error, } = useTaxRegion(id!, undefined, { initialData }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !taxRegion) { return diff --git a/packages/admin/dashboard/src/routes/tax-regions/tax-region-list/tax-region-list.tsx b/packages/admin/dashboard/src/routes/tax-regions/tax-region-list/tax-region-list.tsx index 012305045e..054ae44e53 100644 --- a/packages/admin/dashboard/src/routes/tax-regions/tax-region-list/tax-region-list.tsx +++ b/packages/admin/dashboard/src/routes/tax-regions/tax-region-list/tax-region-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { TaxRegionListView } from "./components/tax-region-list-view" export const TaxRegionsList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { error, } = useTaxRegion(province_id!, undefined, { initialData }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !taxRegion) { return diff --git a/packages/admin/dashboard/src/routes/users/user-detail/user-detail.tsx b/packages/admin/dashboard/src/routes/users/user-detail/user-detail.tsx index 3cf6c5a1b1..5bd07259cc 100644 --- a/packages/admin/dashboard/src/routes/users/user-detail/user-detail.tsx +++ b/packages/admin/dashboard/src/routes/users/user-detail/user-detail.tsx @@ -6,7 +6,7 @@ import { userLoader } from "./loader" import { SingleColumnPageSkeleton } from "../../../components/common/skeleton" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" export const UserDetail = () => { const initialData = useLoaderData() as Awaited> @@ -21,7 +21,7 @@ export const UserDetail = () => { initialData, }) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !user) { return diff --git a/packages/admin/dashboard/src/routes/users/user-list/user-list.tsx b/packages/admin/dashboard/src/routes/users/user-list/user-list.tsx index c80449af83..f2f1e77265 100644 --- a/packages/admin/dashboard/src/routes/users/user-list/user-list.tsx +++ b/packages/admin/dashboard/src/routes/users/user-list/user-list.tsx @@ -1,9 +1,9 @@ import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" import { UserListTable } from "./components/user-list-table" export const UserList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( { const { workflow_execution, isLoading, isError, error } = useWorkflowExecution(id!) - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() if (isLoading || !workflow_execution) { return diff --git a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx index 647eaf967e..d3a2ce8254 100644 --- a/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx +++ b/packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx @@ -1,10 +1,10 @@ import { WorkflowExecutionListTable } from "./components/workflow-execution-list-table" import { SingleColumnPage } from "../../../components/layout/pages" -import { useDashboardExtension } from "../../../extensions" +import { useExtension } from "../../../providers/extension-provider" export const WorkflowExcecutionList = () => { - const { getWidgets } = useDashboardExtension() + const { getWidgets } = useExtension() return ( void + } } declare const __BACKEND_URL__: string | undefined diff --git a/packages/core/framework/src/build-tools/compiler.ts b/packages/core/framework/src/build-tools/compiler.ts index 19de5986fd..c697c0fa42 100644 --- a/packages/core/framework/src/build-tools/compiler.ts +++ b/packages/core/framework/src/build-tools/compiler.ts @@ -1,9 +1,9 @@ -import path from "path" -import chokidar from "chokidar" -import type tsStatic from "typescript" -import { FileSystem, getConfigFile } from "@medusajs/utils" -import { rm, access, constants, copyFile } from "fs/promises" import type { AdminOptions, ConfigModule, Logger } from "@medusajs/types" +import { FileSystem, getConfigFile, getResolvedPlugins } from "@medusajs/utils" +import chokidar from "chokidar" +import { access, constants, copyFile, rm } from "fs/promises" +import path from "path" +import type tsStatic from "typescript" /** * The compiler exposes the opinionated APIs for compiling Medusa @@ -25,7 +25,6 @@ export class Compiler { #logger: Logger #projectRoot: string #tsConfigPath: string - #adminSourceFolder: string #pluginsDistFolder: string #backendIgnoreFiles: string[] #adminOnlyDistFolder: string @@ -35,7 +34,6 @@ export class Compiler { this.#projectRoot = projectRoot this.#logger = logger this.#tsConfigPath = path.join(this.#projectRoot, "tsconfig.json") - this.#adminSourceFolder = path.join(this.#projectRoot, "src/admin") this.#adminOnlyDistFolder = path.join(this.#projectRoot, ".medusa/admin") this.#pluginsDistFolder = path.join(this.#projectRoot, ".medusa/server") this.#backendIgnoreFiles = [ @@ -335,6 +333,7 @@ export class Compiler { build: ( options: AdminOptions & { sources: string[] + plugins: string[] outDir: string } ) => Promise @@ -372,11 +371,30 @@ export class Compiler { ) } + const plugins = await getResolvedPlugins( + this.#projectRoot, + configFile.configModule, + true + ) + + const adminSources = plugins + .map((plugin) => + plugin.admin?.type === "local" ? plugin.admin.resolve : undefined + ) + .filter(Boolean) as string[] + + const adminPlugins = plugins + .map((plugin) => + plugin.admin?.type === "package" ? plugin.admin.resolve : undefined + ) + .filter(Boolean) as string[] + try { this.#logger.info("Compiling frontend source...") await adminBundler.build({ disable: false, - sources: [this.#adminSourceFolder], + sources: adminSources, + plugins: adminPlugins, ...configFile.configModule.admin, outDir: adminOnly ? this.#adminOnlyDistFolder diff --git a/packages/core/types/src/common/config-module.ts b/packages/core/types/src/common/config-module.ts index 46337eaae6..ee6e925304 100644 --- a/packages/core/types/src/common/config-module.ts +++ b/packages/core/types/src/common/config-module.ts @@ -962,12 +962,17 @@ export type InputConfig = Partial< } > +type PluginAdminDetails = { + type: "local" | "package" + resolve: string +} + export type PluginDetails = { resolve: string - adminResolve: string name: string id: string options: Record version: string + admin?: PluginAdminDetails modules?: InputConfigModules } diff --git a/packages/medusa/src/loaders/__tests__/get-resolved-plugins.spec.ts b/packages/core/utils/src/common/__tests__/get-resolved-plugins.spec.ts similarity index 89% rename from packages/medusa/src/loaders/__tests__/get-resolved-plugins.spec.ts rename to packages/core/utils/src/common/__tests__/get-resolved-plugins.spec.ts index 9058c0a4a1..3b96e8fb6f 100644 --- a/packages/medusa/src/loaders/__tests__/get-resolved-plugins.spec.ts +++ b/packages/core/utils/src/common/__tests__/get-resolved-plugins.spec.ts @@ -1,6 +1,7 @@ import path from "path" -import { defineConfig, FileSystem } from "@medusajs/framework/utils" -import { getResolvedPlugins } from "../helpers/resolve-plugins" +import { defineConfig } from "../define-config" +import { FileSystem } from "../file-system" +import { getResolvedPlugins } from "../get-resolved-plugins" const BASE_DIR = path.join(__dirname, "sample-proj") const fs = new FileSystem(BASE_DIR) @@ -34,10 +35,7 @@ describe("getResolvedPlugins | relative paths", () => { expect(plugins).toEqual([ { resolve: path.join(fs.basePath, "./plugins/dummy/.medusa/server/src"), - adminResolve: path.join( - fs.basePath, - "./plugins/dummy/.medusa/server/src/admin" - ), + admin: undefined, name: "my-dummy-plugin", id: "my-dummy-plugin", options: { apiKey: "asecret" }, @@ -75,10 +73,7 @@ describe("getResolvedPlugins | relative paths", () => { expect(plugins).toEqual([ { resolve: path.join(fs.basePath, "./plugins/dummy/.medusa/server/src"), - adminResolve: path.join( - fs.basePath, - "./plugins/dummy/.medusa/server/src/admin" - ), + admin: undefined, name: "my-dummy-plugin", id: "my-dummy-plugin", options: { apiKey: "asecret" }, @@ -151,7 +146,10 @@ describe("getResolvedPlugins | relative paths", () => { expect(plugins).toEqual([ { resolve: path.join(fs.basePath, "./plugins/dummy/.medusa/server/src"), - adminResolve: path.join(fs.basePath, "./plugins/dummy/src/admin"), + admin: { + type: "local", + resolve: path.join(fs.basePath, "./plugins/dummy/src/admin"), + }, name: "my-dummy-plugin", id: "my-dummy-plugin", options: { apiKey: "asecret" }, @@ -198,10 +196,7 @@ describe("getResolvedPlugins | package reference", () => { fs.basePath, "node_modules/@plugins/dummy/.medusa/server/src" ), - adminResolve: path.join( - fs.basePath, - "node_modules/@plugins/dummy/.medusa/server/src/admin" - ), + admin: undefined, name: "my-dummy-plugin", id: "my-dummy-plugin", options: { apiKey: "asecret" }, @@ -243,10 +238,7 @@ describe("getResolvedPlugins | package reference", () => { fs.basePath, "node_modules/@plugins/dummy/.medusa/server/src" ), - adminResolve: path.join( - fs.basePath, - "node_modules/@plugins/dummy/.medusa/server/src/admin" - ), + admin: undefined, name: "my-dummy-plugin", id: "my-dummy-plugin", options: { apiKey: "asecret" }, diff --git a/packages/medusa/src/loaders/helpers/resolve-plugins.ts b/packages/core/utils/src/common/get-resolved-plugins.ts similarity index 84% rename from packages/medusa/src/loaders/helpers/resolve-plugins.ts rename to packages/core/utils/src/common/get-resolved-plugins.ts index 0418d81656..a1c5d7f0b6 100644 --- a/packages/medusa/src/loaders/helpers/resolve-plugins.ts +++ b/packages/core/utils/src/common/get-resolved-plugins.ts @@ -1,7 +1,8 @@ -import path from "path" +import { ConfigModule, PluginDetails } from "@medusajs/types" import fs from "fs/promises" -import { isString, readDir } from "@medusajs/framework/utils" -import { ConfigModule, PluginDetails } from "@medusajs/framework/types" +import path from "path" +import { isString } from "./is-string" +import { readDir } from "./read-dir-recursive" const MEDUSA_APP_SOURCE_PATH = "src" const MEDUSA_PLUGIN_SOURCE_PATH = ".medusa/server/src" @@ -89,13 +90,27 @@ async function resolvePlugin( }) const pluginOptions = options ?? {} + const hasAdmin = + !!pkgJSON.contents.exports?.["./admin"] || !!pluginStaticOptions.srcDir + const isAdminLocal = hasAdmin && !!pluginStaticOptions.srcDir + + const adminConfig = hasAdmin + ? { + type: isAdminLocal ? ("local" as const) : ("package" as const), + resolve: path.join( + isAdminLocal ? pluginStaticOptions.srcDir : name, + "admin" + ), + } + : undefined + return { resolve, name, id: createPluginId(name), options: pluginOptions, version: pkgJSON.contents.version || "0.0.0", - adminResolve: path.join(pluginStaticOptions.srcDir ?? resolve, "admin"), + admin: adminConfig, modules: modules.map((mod) => { return { resolve: `${pluginPath}/${MEDUSA_PLUGIN_SOURCE_PATH}/modules/${mod.name}`, @@ -125,7 +140,10 @@ export async function getResolvedPlugins( resolve: extensionDirectory, name: MEDUSA_PROJECT_NAME, id: createPluginId(MEDUSA_PROJECT_NAME), - adminResolve: path.join(extensionDirectory, "admin"), + admin: { + type: "local", + resolve: path.join(extensionDirectory, "admin"), + }, options: configModule, version: createFileContentHash(process.cwd(), `**`), }) diff --git a/packages/core/utils/src/common/index.ts b/packages/core/utils/src/common/index.ts index 423c1e1b81..34952511c2 100644 --- a/packages/core/utils/src/common/index.ts +++ b/packages/core/utils/src/common/index.ts @@ -27,6 +27,7 @@ export * from "./get-config-file" export * from "./get-duplicates" export * from "./get-iso-string-from-date" export * from "./get-node-version" +export * from "./get-resolved-plugins" export * from "./get-selects-and-relations-from-object-array" export * from "./get-set-difference" export * from "./graceful-shutdown-server" diff --git a/packages/medusa-test-utils/src/medusa-test-runner-utils/use-db.ts b/packages/medusa-test-utils/src/medusa-test-runner-utils/use-db.ts index 24f2f5c0ac..eb6c17f061 100644 --- a/packages/medusa-test-utils/src/medusa-test-runner-utils/use-db.ts +++ b/packages/medusa-test-utils/src/medusa-test-runner-utils/use-db.ts @@ -1,7 +1,10 @@ import type { MedusaAppLoader } from "@medusajs/framework" -import { join } from "path" import { MedusaContainer } from "@medusajs/framework/types" -import { ContainerRegistrationKeys } from "@medusajs/framework/utils" +import { + ContainerRegistrationKeys, + getResolvedPlugins, +} from "@medusajs/framework/utils" +import { join } from "path" /** * Initiates the database connection @@ -53,11 +56,6 @@ export async function syncLinks( } async function loadCustomLinks(directory: string, container: MedusaContainer) { - // TODO: move to framework once settle down - const { - getResolvedPlugins, - } = require("@medusajs/medusa/loaders/helpers/resolve-plugins") - const configModule = container.resolve( ContainerRegistrationKeys.CONFIG_MODULE ) diff --git a/packages/medusa/src/commands/db/generate.ts b/packages/medusa/src/commands/db/generate.ts index 3380622738..73ab736cac 100644 --- a/packages/medusa/src/commands/db/generate.ts +++ b/packages/medusa/src/commands/db/generate.ts @@ -1,16 +1,16 @@ -import { join } from "path" +import { MedusaAppLoader } from "@medusajs/framework" +import { LinkLoader } from "@medusajs/framework/links" +import { logger } from "@medusajs/framework/logger" import { ContainerRegistrationKeys, + getResolvedPlugins, MedusaError, mergePluginModules, } from "@medusajs/framework/utils" -import { LinkLoader } from "@medusajs/framework/links" -import { logger } from "@medusajs/framework/logger" -import { MedusaAppLoader } from "@medusajs/framework" +import { join } from "path" -import { ensureDbExists } from "../utils" import { initializeContainer } from "../../loaders" -import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins" +import { ensureDbExists } from "../utils" const TERMINAL_SIZE = process.stdout.columns diff --git a/packages/medusa/src/commands/db/migrate.ts b/packages/medusa/src/commands/db/migrate.ts index 046210360b..fffc189319 100644 --- a/packages/medusa/src/commands/db/migrate.ts +++ b/packages/medusa/src/commands/db/migrate.ts @@ -3,6 +3,7 @@ import { LinkLoader } from "@medusajs/framework/links" import { logger } from "@medusajs/framework/logger" import { ContainerRegistrationKeys, + getResolvedPlugins, mergePluginModules, } from "@medusajs/framework/utils" import { join } from "path" @@ -10,7 +11,6 @@ import { join } from "path" import { fork } from "child_process" import path from "path" import { initializeContainer } from "../../loaders" -import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins" import { ensureDbExists } from "../utils" import { syncLinks } from "./sync-links" const TERMINAL_SIZE = process.stdout.columns diff --git a/packages/medusa/src/commands/db/rollback.ts b/packages/medusa/src/commands/db/rollback.ts index 23038daf4b..a43d95c774 100644 --- a/packages/medusa/src/commands/db/rollback.ts +++ b/packages/medusa/src/commands/db/rollback.ts @@ -1,16 +1,16 @@ -import { join } from "path" +import { MedusaAppLoader } from "@medusajs/framework" +import { LinkLoader } from "@medusajs/framework/links" +import { logger } from "@medusajs/framework/logger" import { ContainerRegistrationKeys, + getResolvedPlugins, MedusaError, mergePluginModules, } from "@medusajs/framework/utils" -import { LinkLoader } from "@medusajs/framework/links" -import { logger } from "@medusajs/framework/logger" -import { MedusaAppLoader } from "@medusajs/framework" +import { join } from "path" -import { ensureDbExists } from "../utils" import { initializeContainer } from "../../loaders" -import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins" +import { ensureDbExists } from "../utils" const TERMINAL_SIZE = process.stdout.columns diff --git a/packages/medusa/src/commands/db/run-scripts.ts b/packages/medusa/src/commands/db/run-scripts.ts index 67a4241a6c..f443be0f5d 100644 --- a/packages/medusa/src/commands/db/run-scripts.ts +++ b/packages/medusa/src/commands/db/run-scripts.ts @@ -4,6 +4,7 @@ import { logger } from "@medusajs/framework/logger" import { MigrationScriptsMigrator } from "@medusajs/framework/migrations" import { ContainerRegistrationKeys, + getResolvedPlugins, mergePluginModules, } from "@medusajs/framework/utils" import { dirname, join } from "path" @@ -11,7 +12,6 @@ import { dirname, join } from "path" import { MedusaModule } from "@medusajs/framework/modules-sdk" import { MedusaContainer, PluginDetails } from "@medusajs/types" import { initializeContainer } from "../../loaders" -import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins" import { ensureDbExists } from "../utils" const TERMINAL_SIZE = process.stdout.columns diff --git a/packages/medusa/src/commands/db/sync-links.ts b/packages/medusa/src/commands/db/sync-links.ts index 7d91ab0c01..a1be09f985 100644 --- a/packages/medusa/src/commands/db/sync-links.ts +++ b/packages/medusa/src/commands/db/sync-links.ts @@ -1,19 +1,19 @@ +import checkbox from "@inquirer/checkbox" +import { MedusaAppLoader } from "@medusajs/framework" +import { LinkLoader } from "@medusajs/framework/links" +import { logger } from "@medusajs/framework/logger" +import { LinkMigrationsPlannerAction } from "@medusajs/framework/types" +import { + ContainerRegistrationKeys, + getResolvedPlugins, + mergePluginModules, +} from "@medusajs/framework/utils" import boxen from "boxen" import chalk from "chalk" import { join } from "path" -import checkbox from "@inquirer/checkbox" -import { - ContainerRegistrationKeys, - mergePluginModules, -} from "@medusajs/framework/utils" -import { LinkMigrationsPlannerAction } from "@medusajs/framework/types" -import { LinkLoader } from "@medusajs/framework/links" -import { logger } from "@medusajs/framework/logger" -import { MedusaAppLoader } from "@medusajs/framework" -import { ensureDbExists } from "../utils" import { initializeContainer } from "../../loaders" -import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins" +import { ensureDbExists } from "../utils" /** * Groups action tables by their "action" property diff --git a/packages/medusa/src/loaders/admin.ts b/packages/medusa/src/loaders/admin.ts index c5fa3c238b..dd4059f6d9 100644 --- a/packages/medusa/src/loaders/admin.ts +++ b/packages/medusa/src/loaders/admin.ts @@ -5,7 +5,6 @@ import { PluginDetails, } from "@medusajs/framework/types" import { Express } from "express" -import fs from "fs" import path from "path" import { ADMIN_RELATIVE_OUTPUT_DIR } from "../utils" @@ -20,6 +19,7 @@ type IntializedOptions = Required> & AdminOptions & { outDir: string sources?: string[] + plugins?: string[] } const NOT_ALLOWED_PATHS = ["/auth", "/store", "/admin"] @@ -33,15 +33,23 @@ export default async function adminLoader({ const { admin } = configModule const sources: string[] = [] + const pluginAdminPaths: string[] = [] for (const plugin of plugins) { - if (fs.existsSync(plugin.adminResolve)) { - sources.push(plugin.adminResolve) + if (!plugin.admin) { + continue + } + + if (plugin.admin.type === "local") { + sources.push(plugin.admin.resolve) + } else { + pluginAdminPaths.push(plugin.admin.resolve) } } const adminOptions: IntializedOptions = { disable: false, sources, + plugins: pluginAdminPaths, ...admin, outDir: path.join(rootDirectory, ADMIN_RELATIVE_OUTPUT_DIR), } diff --git a/packages/medusa/src/loaders/index.ts b/packages/medusa/src/loaders/index.ts index 97a7cae2b5..f0bbb3a2b3 100644 --- a/packages/medusa/src/loaders/index.ts +++ b/packages/medusa/src/loaders/index.ts @@ -15,6 +15,7 @@ import { } from "@medusajs/framework/types" import { ContainerRegistrationKeys, + getResolvedPlugins, GraphQLSchema, mergePluginModules, promiseAll, @@ -27,7 +28,6 @@ import requestIp from "request-ip" import { v4 } from "uuid" import adminLoader from "./admin" import apiLoader from "./api" -import { getResolvedPlugins } from "./helpers/resolve-plugins" type Options = { directory: string diff --git a/yarn.lock b/yarn.lock index bf8dc56aac..5123a53a03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5267,22 +5267,19 @@ __metadata: "@medusajs/admin-vite-plugin": 2.6.1 "@medusajs/dashboard": 2.6.1 "@medusajs/types": 2.6.1 - "@rollup/plugin-node-resolve": ^16.0.0 "@types/compression": ^1.7.5 "@vitejs/plugin-react": ^4.2.1 autoprefixer: ^10.4.16 compression: ^1.7.4 - copyfiles: ^2.4.1 express: ^4.21.0 get-port: ^5.1.1 glob: ^10.3.10 + outdent: ^0.8.0 postcss: ^8.4.32 tailwindcss: ^3.3.6 tsup: ^8.0.1 typescript: ^5.3.3 vite: ^5.4.14 - peerDependencies: - react-dom: ^18.0.0 languageName: unknown linkType: soft @@ -11296,24 +11293,6 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-node-resolve@npm:^16.0.0": - version: 16.0.0 - resolution: "@rollup/plugin-node-resolve@npm:16.0.0" - dependencies: - "@rollup/pluginutils": ^5.0.1 - "@types/resolve": 1.20.2 - deepmerge: ^4.2.2 - is-module: ^1.0.0 - resolve: ^1.22.1 - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - checksum: b63deb6fc14b37070ccaffacc8c10c9720f28ce7632f4fe2ee77064c0c79bcc3fe060fb77160e673c9fd847307252f25a2983030bd54f1888324063c69ae1399 - languageName: node - linkType: hard - "@rollup/plugin-replace@npm:^5.0.2": version: 5.0.5 resolution: "@rollup/plugin-replace@npm:5.0.5" @@ -17681,24 +17660,6 @@ __metadata: languageName: node linkType: hard -"copyfiles@npm:^2.4.1": - version: 2.4.1 - resolution: "copyfiles@npm:2.4.1" - dependencies: - glob: ^7.0.5 - minimatch: ^3.0.3 - mkdirp: ^1.0.4 - noms: 0.0.0 - through2: ^2.0.1 - untildify: ^4.0.0 - yargs: ^16.1.0 - bin: - copyfiles: copyfiles - copyup: copyfiles - checksum: e65cd055ec9acc14997b0ace83973d73f8d9c68167cbf4293c40b52d100af09a8c8da329042d52dc33422c0a8cbf74c6efb25e9ae088667721653659bd67bf57 - languageName: node - linkType: hard - "core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.36.1": version: 3.37.0 resolution: "core-js-compat@npm:3.37.0" @@ -21493,7 +21454,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:7.2.3, glob@npm:^7.0.5, glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0, glob@npm:~7.2.0": +"glob@npm:7.2.3, glob@npm:^7.1.1, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0, glob@npm:~7.2.0": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -22372,7 +22333,7 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.1, inherits@npm:~2.0.3": +"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 @@ -23208,13 +23169,6 @@ __metadata: languageName: node linkType: hard -"isarray@npm:0.0.1": - version: 0.0.1 - resolution: "isarray@npm:0.0.1" - checksum: ed1e62da617f71fe348907c71743b5ed550448b455f8d269f89a7c7ddb8ae6e962de3dab6a74a237b06f5eb7f6ece7a45ada8ce96d87fe972926530f91ae3311 - languageName: node - linkType: hard - "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" @@ -25454,7 +25408,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:2 || 3, minimatch@npm:^3.0.3, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:2 || 3, minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -25646,7 +25600,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": +"mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" bin: @@ -26214,16 +26168,6 @@ __metadata: languageName: node linkType: hard -"noms@npm:0.0.0": - version: 0.0.0 - resolution: "noms@npm:0.0.0" - dependencies: - inherits: ^2.0.1 - readable-stream: ~1.0.31 - checksum: 7790dbbef45c593b5444b361cb9cde3260244ab66aaa199c0728d334525eb69df96231115cff260b71b92fc7a6915a642aa22f2f8448696d8dd6e7d7cebfccce - languageName: node - linkType: hard - "nopt@npm:^7.0.0": version: 7.2.1 resolution: "nopt@npm:7.2.1" @@ -29076,7 +29020,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.5": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -29102,18 +29046,6 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:~1.0.31": - version: 1.0.34 - resolution: "readable-stream@npm:1.0.34" - dependencies: - core-util-is: ~1.0.0 - inherits: ~2.0.1 - isarray: 0.0.1 - string_decoder: ~0.10.x - checksum: 02272551396ed8930ddee1a088bdf0379f0f7cc47ac49ed8804e998076cb7daec9fbd2b1fd9c0490ec72e56e8bb3651abeb8080492b8e0a9c3f2158330908ed6 - languageName: node - linkType: hard - "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -31399,13 +31331,6 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:~0.10.x": - version: 0.10.31 - resolution: "string_decoder@npm:0.10.31" - checksum: 1c628d78f974aa7539c496029f48e7019acc32487fc695464f9d6bdfec98edd7d933a06b3216bc2016918f6e75074c611d84430a53cb0e43071597d6c1ac5e25 - languageName: node - linkType: hard - "string_decoder@npm:~1.1.1": version: 1.1.1 resolution: "string_decoder@npm:1.1.1" @@ -31942,16 +31867,6 @@ __metadata: languageName: node linkType: hard -"through2@npm:^2.0.1": - version: 2.0.5 - resolution: "through2@npm:2.0.5" - dependencies: - readable-stream: ~2.3.6 - xtend: ~4.0.1 - checksum: cbfe5b57943fa12b4f8c043658c2a00476216d79c014895cef1ac7a1d9a8b31f6b438d0e53eecbb81054b93128324a82ecd59ec1a4f91f01f7ac113dcb14eade - languageName: node - linkType: hard - "through@npm:>=2.2.7 <3, through@npm:^2.3.6, through@npm:^2.3.8": version: 2.3.8 resolution: "through@npm:2.3.8" @@ -34266,7 +34181,7 @@ __metadata: languageName: node linkType: hard -"xtend@npm:^4.0.0, xtend@npm:^4.0.2, xtend@npm:~4.0.0, xtend@npm:~4.0.1": +"xtend@npm:^4.0.0, xtend@npm:^4.0.2, xtend@npm:~4.0.0": version: 4.0.2 resolution: "xtend@npm:4.0.2" checksum: 366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e @@ -34422,7 +34337,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^16.1.0, yargs@npm:^16.1.1": +"yargs@npm:^16.1.1": version: 16.2.0 resolution: "yargs@npm:16.2.0" dependencies: