fix
This commit is contained in:
@@ -27,6 +27,9 @@ export const ADMIN_SYNC_A1_PATH = (companyId: string) =>
|
|||||||
export const ADMIN_STAFF_ROLE_PATH = (userId: string) =>
|
export const ADMIN_STAFF_ROLE_PATH = (userId: string) =>
|
||||||
`/api/admin/users/${encodeURIComponent(userId)}/staff-role`;
|
`/api/admin/users/${encodeURIComponent(userId)}/staff-role`;
|
||||||
|
|
||||||
|
/** Matches API `platformDemoCompanyName` (catalog/prompt_repair.go). */
|
||||||
|
export const PLATFORM_DEMO_COMPANY_NAME = "Platform Demo";
|
||||||
|
|
||||||
export const PAGE_SIZE = 25;
|
export const PAGE_SIZE = 25;
|
||||||
|
|
||||||
export type PlatformStaffRole = "admin" | "developer" | "support_staff";
|
export type PlatformStaffRole = "admin" | "developer" | "support_staff";
|
||||||
@@ -217,7 +220,7 @@ export type CloneCatalogResult = {
|
|||||||
counts: Record<string, number>;
|
counts: Record<string, number>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Copy source company catalog into the admin sandbox (home / dest). Source is unchanged. */
|
/** Copy source company catalog into dest (explicit id preferred). Source is unchanged. */
|
||||||
export async function cloneAdminCompanyCatalog(
|
export async function cloneAdminCompanyCatalog(
|
||||||
sourceCompanyId: string,
|
sourceCompanyId: string,
|
||||||
opts?: { destCompanyId?: string }
|
opts?: { destCompanyId?: string }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** German (de) UI pack — keys must stay in sync with en.ts. */
|
/** German (de) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const de: MessageDict = {
|
export const de: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const de: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Abbrechen",
|
"admin.users.cloneCatalogCancel": "Abbrechen",
|
||||||
"admin.users.cloneCatalogConfirm": "Katalog kopieren",
|
"admin.users.cloneCatalogConfirm": "Katalog kopieren",
|
||||||
"admin.users.cloneDestFallback": "Ihr Sandbox-Unternehmen",
|
"admin.users.cloneDestFallback": "Ihr Sandbox-Unternehmen",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "A1 synchronisieren",
|
"admin.users.syncA1": "A1 synchronisieren",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "A1-Katalog synchronisieren",
|
"admin.users.syncA1Title": "A1-Katalog synchronisieren",
|
||||||
@@ -2307,7 +2310,6 @@ export const de: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "A1-Sync für {name} fehlgeschlagen.",
|
"flash.admin.syncA1Error": "A1-Sync für {name} fehlgeschlagen.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssignedShort": "Plan zugewiesen.",
|
"flash.admin.planAssignedShort": "Plan zugewiesen.",
|
||||||
"flash.admin.creditsUpdated": "Credits aktualisiert.",
|
"flash.admin.creditsUpdated": "Credits aktualisiert.",
|
||||||
"flash.admin.cyclesProcessed": "Abrechnungszyklen verarbeitet: {count}",
|
"flash.admin.cyclesProcessed": "Abrechnungszyklen verarbeitet: {count}",
|
||||||
|
|||||||
@@ -839,6 +839,9 @@ export const en: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Cancel",
|
"admin.users.cloneCatalogCancel": "Cancel",
|
||||||
"admin.users.cloneCatalogConfirm": "Copy catalog",
|
"admin.users.cloneCatalogConfirm": "Copy catalog",
|
||||||
"admin.users.cloneDestFallback": "your sandbox company",
|
"admin.users.cloneDestFallback": "your sandbox company",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Sync A1",
|
"admin.users.syncA1": "Sync A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Sync A1 catalog",
|
"admin.users.syncA1Title": "Sync A1 catalog",
|
||||||
@@ -2333,10 +2336,9 @@ export const en: MessageDict = {
|
|||||||
"flash.admin.staffRoleUpdated": "Staff role updated for {email}.",
|
"flash.admin.staffRoleUpdated": "Staff role updated for {email}.",
|
||||||
"flash.admin.staffRoleUnavailable": "Staff role updates are not available on this server yet.",
|
"flash.admin.staffRoleUnavailable": "Staff role updates are not available on this server yet.",
|
||||||
"flash.admin.planAssigned": "Plan assigned to {name}.",
|
"flash.admin.planAssigned": "Plan assigned to {name}.",
|
||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} products with mapped category. Open Products — uncategorized SKUs need dump backfill or categorize, not another Fix.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} products with mapped category. Open Products ΓÇö uncategorized SKUs need dump backfill or categorize, not another Fix.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Sync A1 failed for {name}.",
|
"flash.admin.syncA1Error": "Sync A1 failed for {name}.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch active company to Platform Demo (or your staff home), then clone again. Clone refuses to overwrite A1.",
|
|
||||||
"flash.admin.planAssignedShort": "Plan assigned.",
|
"flash.admin.planAssignedShort": "Plan assigned.",
|
||||||
"flash.admin.creditsUpdated": "Credits updated.",
|
"flash.admin.creditsUpdated": "Credits updated.",
|
||||||
"flash.admin.cyclesProcessed": "Billing cycles processed: {count}",
|
"flash.admin.cyclesProcessed": "Billing cycles processed: {count}",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** Spanish (es) UI pack — keys must stay in sync with en.ts. */
|
/** Spanish (es) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const es: MessageDict = {
|
export const es: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const es: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Cancelar",
|
"admin.users.cloneCatalogCancel": "Cancelar",
|
||||||
"admin.users.cloneCatalogConfirm": "Copiar catálogo",
|
"admin.users.cloneCatalogConfirm": "Copiar catálogo",
|
||||||
"admin.users.cloneDestFallback": "tu empresa sandbox",
|
"admin.users.cloneDestFallback": "tu empresa sandbox",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Sincronizar A1",
|
"admin.users.syncA1": "Sincronizar A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Sincronizar catálogo A1",
|
"admin.users.syncA1Title": "Sincronizar catálogo A1",
|
||||||
@@ -2306,7 +2309,6 @@ export const es: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Falló la sincronización A1 de {name}.",
|
"flash.admin.syncA1Error": "Falló la sincronización A1 de {name}.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "Plan asignado a {name}.",
|
"flash.admin.planAssigned": "Plan asignado a {name}.",
|
||||||
"flash.admin.planAssignedShort": "Plan asignado.",
|
"flash.admin.planAssignedShort": "Plan asignado.",
|
||||||
"flash.admin.creditsUpdated": "Créditos actualizados.",
|
"flash.admin.creditsUpdated": "Créditos actualizados.",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** French (fr) UI pack — keys must stay in sync with en.ts. */
|
/** French (fr) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const fr: MessageDict = {
|
export const fr: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const fr: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Annuler",
|
"admin.users.cloneCatalogCancel": "Annuler",
|
||||||
"admin.users.cloneCatalogConfirm": "Copier le catalogue",
|
"admin.users.cloneCatalogConfirm": "Copier le catalogue",
|
||||||
"admin.users.cloneDestFallback": "votre entreprise sandbox",
|
"admin.users.cloneDestFallback": "votre entreprise sandbox",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Synchroniser A1",
|
"admin.users.syncA1": "Synchroniser A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Synchroniser le catalogue A1",
|
"admin.users.syncA1Title": "Synchroniser le catalogue A1",
|
||||||
@@ -2306,7 +2309,6 @@ export const fr: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Échec de la synchronisation A1 pour {name}.",
|
"flash.admin.syncA1Error": "Échec de la synchronisation A1 pour {name}.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "Offre assignée à {name}.",
|
"flash.admin.planAssigned": "Offre assignée à {name}.",
|
||||||
"flash.admin.planAssignedShort": "Offre assignée.",
|
"flash.admin.planAssignedShort": "Offre assignée.",
|
||||||
"flash.admin.creditsUpdated": "Crédits mis à jour.",
|
"flash.admin.creditsUpdated": "Crédits mis à jour.",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** Italian (it) UI pack — keys must stay in sync with en.ts. */
|
/** Italian (it) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const it: MessageDict = {
|
export const it: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const it: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Annulla",
|
"admin.users.cloneCatalogCancel": "Annulla",
|
||||||
"admin.users.cloneCatalogConfirm": "Copia catalogo",
|
"admin.users.cloneCatalogConfirm": "Copia catalogo",
|
||||||
"admin.users.cloneDestFallback": "la tua azienda sandbox",
|
"admin.users.cloneDestFallback": "la tua azienda sandbox",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Sincronizza A1",
|
"admin.users.syncA1": "Sincronizza A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Sincronizza catalogo A1",
|
"admin.users.syncA1Title": "Sincronizza catalogo A1",
|
||||||
@@ -2306,7 +2309,6 @@ export const it: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Sincronizzazione A1 per {name} non riuscita.",
|
"flash.admin.syncA1Error": "Sincronizzazione A1 per {name} non riuscita.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "Piano assegnato a {name}.",
|
"flash.admin.planAssigned": "Piano assegnato a {name}.",
|
||||||
"flash.admin.planAssignedShort": "Piano assegnato.",
|
"flash.admin.planAssignedShort": "Piano assegnato.",
|
||||||
"flash.admin.creditsUpdated": "Crediti aggiornati.",
|
"flash.admin.creditsUpdated": "Crediti aggiornati.",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** Japanese (ja) UI pack — keys must stay in sync with en.ts. */
|
/** Japanese (ja) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const ja: MessageDict = {
|
export const ja: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const ja: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "ã‚ャンセル",
|
"admin.users.cloneCatalogCancel": "ã‚ャンセル",
|
||||||
"admin.users.cloneCatalogConfirm": "ã‚«ã‚¿ãƒã‚°ã‚’コピー",
|
"admin.users.cloneCatalogConfirm": "ã‚«ã‚¿ãƒã‚°ã‚’コピー",
|
||||||
"admin.users.cloneDestFallback": "サンドボックス会社",
|
"admin.users.cloneDestFallback": "サンドボックス会社",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "A1を同期",
|
"admin.users.syncA1": "A1を同期",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "A1カタログを同期",
|
"admin.users.syncA1Title": "A1カタログを同期",
|
||||||
@@ -2306,7 +2309,6 @@ export const ja: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "{name} のA1同期に失敗しました。",
|
"flash.admin.syncA1Error": "{name} のA1同期に失敗しました。",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "{name} ã«ãƒ—ランを割り当ã¦ã¾ã—ãŸã€‚",
|
"flash.admin.planAssigned": "{name} ã«ãƒ—ランを割り当ã¦ã¾ã—ãŸã€‚",
|
||||||
"flash.admin.planAssignedShort": "プランを割り当ã¦ã¾ã—ãŸã€‚",
|
"flash.admin.planAssignedShort": "プランを割り当ã¦ã¾ã—ãŸã€‚",
|
||||||
"flash.admin.creditsUpdated": "クレジットを更新ã—ã¾ã—ãŸã€‚",
|
"flash.admin.creditsUpdated": "クレジットを更新ã—ã¾ã—ãŸã€‚",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** Dutch (nl) UI pack — keys must stay in sync with en.ts. */
|
/** Dutch (nl) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const nl: MessageDict = {
|
export const nl: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const nl: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Annuleren",
|
"admin.users.cloneCatalogCancel": "Annuleren",
|
||||||
"admin.users.cloneCatalogConfirm": "Catalogus kopiëren",
|
"admin.users.cloneCatalogConfirm": "Catalogus kopiëren",
|
||||||
"admin.users.cloneDestFallback": "je sandboxbedrijf",
|
"admin.users.cloneDestFallback": "je sandboxbedrijf",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "A1 synchroniseren",
|
"admin.users.syncA1": "A1 synchroniseren",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "A1-catalogus synchroniseren",
|
"admin.users.syncA1Title": "A1-catalogus synchroniseren",
|
||||||
@@ -2306,7 +2309,6 @@ export const nl: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "A1-synchronisatie voor {name} mislukt.",
|
"flash.admin.syncA1Error": "A1-synchronisatie voor {name} mislukt.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "Plan toegewezen aan {name}.",
|
"flash.admin.planAssigned": "Plan toegewezen aan {name}.",
|
||||||
"flash.admin.planAssignedShort": "Plan toegewezen.",
|
"flash.admin.planAssignedShort": "Plan toegewezen.",
|
||||||
"flash.admin.creditsUpdated": "Credits bijgewerkt.",
|
"flash.admin.creditsUpdated": "Credits bijgewerkt.",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** Polish (pl) UI pack — keys must stay in sync with en.ts. */
|
/** Polish (pl) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const pl: MessageDict = {
|
export const pl: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const pl: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Anuluj",
|
"admin.users.cloneCatalogCancel": "Anuluj",
|
||||||
"admin.users.cloneCatalogConfirm": "Kopiuj katalog",
|
"admin.users.cloneCatalogConfirm": "Kopiuj katalog",
|
||||||
"admin.users.cloneDestFallback": "twoja firma sandbox",
|
"admin.users.cloneDestFallback": "twoja firma sandbox",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Synchronizuj A1",
|
"admin.users.syncA1": "Synchronizuj A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Synchronizuj katalog A1",
|
"admin.users.syncA1Title": "Synchronizuj katalog A1",
|
||||||
@@ -2306,7 +2309,6 @@ export const pl: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Synchronizacja A1 dla {name} nie powiodła się.",
|
"flash.admin.syncA1Error": "Synchronizacja A1 dla {name} nie powiodła się.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "Przypisano plan do {name}.",
|
"flash.admin.planAssigned": "Przypisano plan do {name}.",
|
||||||
"flash.admin.planAssignedShort": "Przypisano plan.",
|
"flash.admin.planAssignedShort": "Przypisano plan.",
|
||||||
"flash.admin.creditsUpdated": "Zaktualizowano kredyty.",
|
"flash.admin.creditsUpdated": "Zaktualizowano kredyty.",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { MessageDict } from "./types";
|
import type { MessageDict } from "./types";
|
||||||
|
|
||||||
/** Portuguese (pt) UI pack — keys must stay in sync with en.ts. */
|
/** Portuguese (pt) UI pack — keys must stay in sync with en.ts. */
|
||||||
export const pt: MessageDict = {
|
export const pt: MessageDict = {
|
||||||
@@ -812,6 +812,9 @@ export const pt: MessageDict = {
|
|||||||
"admin.users.cloneCatalogCancel": "Cancelar",
|
"admin.users.cloneCatalogCancel": "Cancelar",
|
||||||
"admin.users.cloneCatalogConfirm": "Copiar catálogo",
|
"admin.users.cloneCatalogConfirm": "Copiar catálogo",
|
||||||
"admin.users.cloneDestFallback": "a sua empresa sandbox",
|
"admin.users.cloneDestFallback": "a sua empresa sandbox",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Sincronizar A1",
|
"admin.users.syncA1": "Sincronizar A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Sincronizar catálogo A1",
|
"admin.users.syncA1Title": "Sincronizar catálogo A1",
|
||||||
@@ -2306,7 +2309,6 @@ export const pt: MessageDict = {
|
|||||||
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Falha na sincronização A1 de {name}.",
|
"flash.admin.syncA1Error": "Falha na sincronização A1 de {name}.",
|
||||||
"flash.admin.cloneDestMissing": "No sandbox destination. Switch to Platform Demo (staff home), then clone again.",
|
|
||||||
"flash.admin.planAssigned": "Plano atribuÃdo a {name}.",
|
"flash.admin.planAssigned": "Plano atribuÃdo a {name}.",
|
||||||
"flash.admin.planAssignedShort": "Plano atribuÃdo.",
|
"flash.admin.planAssignedShort": "Plano atribuÃdo.",
|
||||||
"flash.admin.creditsUpdated": "Créditos atualizados.",
|
"flash.admin.creditsUpdated": "Créditos atualizados.",
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
import type { MessageDict } from "./types.ts";
|
import type { MessageDict } from "./types.ts";
|
||||||
|
|
||||||
/** Slovenian (sl) UI strings for admin Fix A1 — ready pack. Not registered in UI_LOCALES yet (avoid inventing locale switcher). */
|
/** Slovenian (sl) UI strings for admin Fix A1 — ready pack. Not registered in UI_LOCALES yet (avoid inventing locale switcher). */
|
||||||
export const sl: MessageDict = {
|
export const sl: MessageDict = {
|
||||||
|
"admin.users.cloneCatalog": "Copy to my company",
|
||||||
|
"admin.users.cloneCatalogAria": "Copy {name} catalog into your sandbox company",
|
||||||
|
"admin.users.cloneCatalogTitle": "Copy company catalog",
|
||||||
|
"admin.users.cloneCatalogDesc": "Stay on your admin account. Source data is not changed.",
|
||||||
|
"admin.users.cloneCatalogFrom": "Source: {name}",
|
||||||
|
"admin.users.cloneCatalogInto": "Destination: {name}",
|
||||||
|
"admin.users.cloneCatalogWarning": "Replaces categories, feeds, products, attributes, mappings, and brand on the destination. Plan, billing, members, API keys, and store connectors are not copied.",
|
||||||
|
"admin.users.cloneCatalogCancel": "Cancel",
|
||||||
|
"admin.users.cloneCatalogConfirm": "Copy catalog",
|
||||||
|
"admin.users.cloneDestFallback": "your sandbox company",
|
||||||
|
"admin.users.cloneDestLabel": "Destination company",
|
||||||
|
"admin.users.cloneDestSelect": "Select destination",
|
||||||
|
"admin.users.cloneDestRequired": "Choose a destination company different from the source.",
|
||||||
"admin.users.syncA1": "Sinhroniziraj A1",
|
"admin.users.syncA1": "Sinhroniziraj A1",
|
||||||
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
"admin.users.syncA1Aria": "Sync A1 categories from dump and repair catalog hygiene for {name}",
|
||||||
"admin.users.syncA1Title": "Sinhroniziraj katalog A1",
|
"admin.users.syncA1Title": "Sinhroniziraj katalog A1",
|
||||||
@@ -10,7 +23,7 @@ export const sl: MessageDict = {
|
|||||||
"admin.users.syncA1Warning": "Requires descrybe_new.sql on the API server (scripts/seed/ or SEED_A1_MYSQL_DUMP) for dump category coverage. Without a dump, only DB hygiene runs. No mass reprocess.",
|
"admin.users.syncA1Warning": "Requires descrybe_new.sql on the API server (scripts/seed/ or SEED_A1_MYSQL_DUMP) for dump category coverage. Without a dump, only DB hygiene runs. No mass reprocess.",
|
||||||
"admin.users.syncA1Cancel": "Prekliči",
|
"admin.users.syncA1Cancel": "Prekliči",
|
||||||
"admin.users.syncA1Confirm": "Sinhroniziraj A1",
|
"admin.users.syncA1Confirm": "Sinhroniziraj A1",
|
||||||
|
"flash.admin.catalogCloned": "Copied {source} into {dest}: {products} products, {categories} taxonomy categories, {mapped_with} with mapped category.",
|
||||||
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
"flash.admin.syncA1Success": "Synced A1 for {name}: dump_mapped {dump_mapped} ({dump_status}), prompts {prompts}, hashes {hashes}, processed←mapped {categories}, mapped←processed {mapped_backfilled}. Coverage: {mapped_with}/{mapped_total} ({taxonomy} taxonomy).",
|
||||||
"flash.admin.syncA1Error": "Sinhronizacija A1 za {name} ni uspela.",
|
"flash.admin.syncA1Error": "Sinhronizacija A1 za {name} ni uspela.",
|
||||||
"flash.admin.cloneDestMissing": "Ni ciljnega sandbox podjetja. Preklopite na Platform Demo, nato klonirajte.",
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
import { formatCredits, formatDate } from "$lib/utils";
|
import { formatCredits, formatDate } from "$lib/utils";
|
||||||
import {
|
import {
|
||||||
PAGE_SIZE,
|
PAGE_SIZE,
|
||||||
|
PLATFORM_DEMO_COMPANY_NAME,
|
||||||
STAFF_ROLE_OPTIONS,
|
STAFF_ROLE_OPTIONS,
|
||||||
assignAdminPlan,
|
assignAdminPlan,
|
||||||
cloneAdminCompanyCatalog,
|
cloneAdminCompanyCatalog,
|
||||||
@@ -93,23 +94,23 @@
|
|||||||
|
|
||||||
let cloneOpen = $state(false);
|
let cloneOpen = $state(false);
|
||||||
let cloneCompany = $state<AdminOrgCompany | null>(null);
|
let cloneCompany = $state<AdminOrgCompany | null>(null);
|
||||||
|
let cloneDestId = $state("");
|
||||||
|
let cloneDestOptions = $state<AdminOrgCompany[]>([]);
|
||||||
|
|
||||||
let syncOpen = $state(false);
|
let syncOpen = $state(false);
|
||||||
let syncCompany = $state<AdminOrgCompany | null>(null);
|
let syncCompany = $state<AdminOrgCompany | null>(null);
|
||||||
|
|
||||||
|
const cloneDestLabel = $derived.by(() => {
|
||||||
|
const selected = cloneDestOptions.find((c) => c.id === cloneDestId);
|
||||||
|
if (selected?.name) return selected.name;
|
||||||
|
return i18n.t("admin.users.cloneDestFallback");
|
||||||
|
});
|
||||||
|
|
||||||
const usersPage = $derived(Math.floor(usersOffset / PAGE_SIZE) + 1);
|
const usersPage = $derived(Math.floor(usersOffset / PAGE_SIZE) + 1);
|
||||||
const usersPages = $derived(Math.max(1, Math.ceil(usersTotal / PAGE_SIZE)));
|
const usersPages = $derived(Math.max(1, Math.ceil(usersTotal / PAGE_SIZE)));
|
||||||
const companiesPage = $derived(Math.floor(companiesOffset / PAGE_SIZE) + 1);
|
const companiesPage = $derived(Math.floor(companiesOffset / PAGE_SIZE) + 1);
|
||||||
const companiesPages = $derived(Math.max(1, Math.ceil(companiesTotal / PAGE_SIZE)));
|
const companiesPages = $derived(Math.max(1, Math.ceil(companiesTotal / PAGE_SIZE)));
|
||||||
|
|
||||||
const cloneDestLabel = $derived.by(() => {
|
|
||||||
const me = authSession.me;
|
|
||||||
const home = me?.staff_home_company;
|
|
||||||
if (home?.name) return home.name;
|
|
||||||
if (me?.company?.name) return me.company.name;
|
|
||||||
return i18n.t("admin.users.cloneDestFallback");
|
|
||||||
});
|
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const gate = await requirePlatformAdmin();
|
const gate = await requirePlatformAdmin();
|
||||||
if (!gate.ok) {
|
if (!gate.ok) {
|
||||||
@@ -359,11 +360,49 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openCloneDialog(company: AdminOrgCompany) {
|
async function openCloneDialog(company: AdminOrgCompany) {
|
||||||
cloneCompany = company;
|
cloneCompany = company;
|
||||||
cloneOpen = true;
|
cloneOpen = true;
|
||||||
error = "";
|
error = "";
|
||||||
success = "";
|
success = "";
|
||||||
|
cloneDestId = "";
|
||||||
|
const byId = new Map<string, AdminOrgCompany>();
|
||||||
|
for (const c of companies) {
|
||||||
|
if (c.id !== company.id) byId.set(c.id, c);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const demoRes = await listAdminCompanies({
|
||||||
|
limit: PAGE_SIZE,
|
||||||
|
offset: 0,
|
||||||
|
q: PLATFORM_DEMO_COMPANY_NAME
|
||||||
|
});
|
||||||
|
for (const c of demoRes.companies) {
|
||||||
|
if (c.id !== company.id) byId.set(c.id, c);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
/* keep page companies as fallback */
|
||||||
|
}
|
||||||
|
const me = authSession.me;
|
||||||
|
const home = me?.staff_home_company;
|
||||||
|
if (home?.id && home.id !== company.id && home.name) {
|
||||||
|
byId.set(home.id, { id: home.id, name: home.name });
|
||||||
|
}
|
||||||
|
for (const c of me?.companies ?? []) {
|
||||||
|
if (c.id && c.id !== company.id && c.name) {
|
||||||
|
byId.set(c.id, { id: c.id, name: c.name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const opts = [...byId.values()].sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
cloneDestOptions = opts;
|
||||||
|
const demo =
|
||||||
|
opts.find((c) => c.name.trim().toLowerCase() === PLATFORM_DEMO_COMPANY_NAME.toLowerCase()) ??
|
||||||
|
null;
|
||||||
|
const homeId = (me?.staff_home_company_id || me?.staff_home_company?.id || "").trim();
|
||||||
|
cloneDestId =
|
||||||
|
demo?.id ||
|
||||||
|
(homeId && homeId !== company.id ? homeId : "") ||
|
||||||
|
opts[0]?.id ||
|
||||||
|
"";
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSyncDialog(company: AdminOrgCompany) {
|
function openSyncDialog(company: AdminOrgCompany) {
|
||||||
@@ -373,6 +412,54 @@
|
|||||||
success = "";
|
success = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function confirmCloneCatalog() {
|
||||||
|
if (!cloneCompany) return;
|
||||||
|
const destId = cloneDestId.trim();
|
||||||
|
if (!destId || destId === cloneCompany.id) {
|
||||||
|
error = i18n.t("admin.users.cloneDestRequired");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
busy = true;
|
||||||
|
error = "";
|
||||||
|
success = "";
|
||||||
|
try {
|
||||||
|
const res = await cloneAdminCompanyCatalog(cloneCompany.id, {
|
||||||
|
destCompanyId: destId
|
||||||
|
});
|
||||||
|
const products = Number(res.counts?.raw_products ?? 0);
|
||||||
|
const categories = Number(res.counts?.categories ?? 0);
|
||||||
|
const mappedWith = Number(res.counts?.mapped_with_category ?? 0);
|
||||||
|
const activeDest = (res.active_company_id || res.dest_company_id || "").trim();
|
||||||
|
success = i18n.t("flash.admin.catalogCloned", {
|
||||||
|
source: cloneCompany.name,
|
||||||
|
dest: cloneDestLabel,
|
||||||
|
products: String(products),
|
||||||
|
categories: String(categories),
|
||||||
|
mapped_with: String(mappedWith)
|
||||||
|
});
|
||||||
|
cloneOpen = false;
|
||||||
|
cloneCompany = null;
|
||||||
|
cloneDestId = "";
|
||||||
|
cloneDestOptions = [];
|
||||||
|
if (activeDest) {
|
||||||
|
try {
|
||||||
|
await api("/api/auth/select-company", {
|
||||||
|
method: "POST",
|
||||||
|
body: { company_id: activeDest }
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
/* clone handler may already have switched the session */
|
||||||
|
}
|
||||||
|
window.location.assign("/products");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
error = failureMessage(err, "Clone catalog failed");
|
||||||
|
} finally {
|
||||||
|
busy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function confirmSyncA1() {
|
async function confirmSyncA1() {
|
||||||
if (!syncCompany) return;
|
if (!syncCompany) return;
|
||||||
busy = true;
|
busy = true;
|
||||||
@@ -409,56 +496,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function confirmCloneCatalog() {
|
|
||||||
if (!cloneCompany) return;
|
|
||||||
busy = true;
|
|
||||||
error = "";
|
|
||||||
success = "";
|
|
||||||
try {
|
|
||||||
const me = authSession.me;
|
|
||||||
const destId =
|
|
||||||
me?.staff_home_company_id?.trim() ||
|
|
||||||
me?.staff_home_company?.id?.trim() ||
|
|
||||||
undefined;
|
|
||||||
if (!destId && me?.company?.id && me.company.id === cloneCompany.id) {
|
|
||||||
error = i18n.t("flash.admin.cloneDestMissing");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const res = await cloneAdminCompanyCatalog(cloneCompany.id, {
|
|
||||||
destCompanyId: destId
|
|
||||||
});
|
|
||||||
const products = Number(res.counts?.raw_products ?? 0);
|
|
||||||
const categories = Number(res.counts?.categories ?? 0);
|
|
||||||
const mappedWith = Number(res.counts?.mapped_with_category ?? 0);
|
|
||||||
const activeDest = (res.active_company_id || res.dest_company_id || "").trim();
|
|
||||||
success = i18n.t("flash.admin.catalogCloned", {
|
|
||||||
source: cloneCompany.name,
|
|
||||||
dest: cloneDestLabel,
|
|
||||||
products: String(products),
|
|
||||||
categories: String(categories),
|
|
||||||
mapped_with: String(mappedWith)
|
|
||||||
});
|
|
||||||
cloneOpen = false;
|
|
||||||
cloneCompany = null;
|
|
||||||
if (activeDest) {
|
|
||||||
try {
|
|
||||||
await api("/api/auth/select-company", {
|
|
||||||
method: "POST",
|
|
||||||
body: { company_id: activeDest }
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
/* clone handler may already have switched the session */
|
|
||||||
}
|
|
||||||
window.location.assign("/products");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
error = failureMessage(err, "Clone catalog failed");
|
|
||||||
} finally {
|
|
||||||
busy = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendSetPasswordEmails(userId?: string) {
|
async function sendSetPasswordEmails(userId?: string) {
|
||||||
busy = true;
|
busy = true;
|
||||||
error = "";
|
error = "";
|
||||||
@@ -998,9 +1035,15 @@
|
|||||||
{i18n.t("admin.users.cloneCatalogFrom", { name: cloneCompany.name })}
|
{i18n.t("admin.users.cloneCatalogFrom", { name: cloneCompany.name })}
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
<p class="text-sm text-muted-foreground">
|
<div class="space-y-2">
|
||||||
{i18n.t("admin.users.cloneCatalogInto", { name: cloneDestLabel })}
|
<Label for="clone-dest">{i18n.t("admin.users.cloneDestLabel")}</Label>
|
||||||
</p>
|
<Select id="clone-dest" bind:value={cloneDestId} data-testid="admin-clone-dest">
|
||||||
|
<option value="">{i18n.t("admin.users.cloneDestSelect")}</option>
|
||||||
|
{#each cloneDestOptions as dest}
|
||||||
|
<option value={dest.id}>{dest.name}</option>
|
||||||
|
{/each}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
<p class="text-xs text-muted-foreground">
|
<p class="text-xs text-muted-foreground">
|
||||||
{i18n.t("admin.users.cloneCatalogWarning")}
|
{i18n.t("admin.users.cloneCatalogWarning")}
|
||||||
</p>
|
</p>
|
||||||
@@ -1012,11 +1055,18 @@
|
|||||||
onclick={() => {
|
onclick={() => {
|
||||||
cloneOpen = false;
|
cloneOpen = false;
|
||||||
cloneCompany = null;
|
cloneCompany = null;
|
||||||
|
cloneDestId = "";
|
||||||
|
cloneDestOptions = [];
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{i18n.t("admin.users.cloneCatalogCancel")}
|
{i18n.t("admin.users.cloneCatalogCancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="button" loading={busy} onclick={() => confirmCloneCatalog()}>
|
<Button
|
||||||
|
type="button"
|
||||||
|
loading={busy}
|
||||||
|
disabled={!cloneDestId || cloneDestId === cloneCompany?.id}
|
||||||
|
onclick={() => confirmCloneCatalog()}
|
||||||
|
>
|
||||||
{i18n.t("admin.users.cloneCatalogConfirm")}
|
{i18n.t("admin.users.cloneCatalogConfirm")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user