@webiny/api-headless-cms 6.0.0-rc.1 → 6.0.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/constants.d.ts +2 -1
- package/constants.js +4 -0
- package/constants.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/createEntryData.js +4 -3
- package/crud/contentEntry/entryDataFactories/createEntryData.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/createEntryRevisionFromData.js +4 -3
- package/crud/contentEntry/entryDataFactories/createEntryRevisionFromData.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/createPublishEntryData.js +4 -1
- package/crud/contentEntry/entryDataFactories/createPublishEntryData.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/createRepublishEntryData.js +4 -1
- package/crud/contentEntry/entryDataFactories/createRepublishEntryData.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/createUnpublishEntryData.js +2 -1
- package/crud/contentEntry/entryDataFactories/createUnpublishEntryData.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/createUpdateEntryData.js +4 -3
- package/crud/contentEntry/entryDataFactories/createUpdateEntryData.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/system.d.ts +10 -0
- package/crud/contentEntry/entryDataFactories/system.js +14 -0
- package/crud/contentEntry/entryDataFactories/system.js.map +1 -0
- package/crud/contentModel/validation.d.ts +9 -9
- package/crud/contentModel/validation.js +3 -3
- package/crud/contentModel/validation.js.map +1 -1
- package/domain/contentModel/errors.d.ts +1 -1
- package/domain/contentModel/errors.js.map +1 -1
- package/domain/contentModel/schemas.d.ts +126 -8
- package/domain/contentModel/schemas.js +12 -13
- package/domain/contentModel/schemas.js.map +1 -1
- package/export/graphql/index.js +1 -1
- package/export/graphql/index.js.map +1 -1
- package/features/contentModel/CreateModel/CreateModelRepository.js +4 -1
- package/features/contentModel/CreateModel/CreateModelRepository.js.map +1 -1
- package/features/contentModel/CreateModelFrom/CreateModelFromRepository.js +12 -3
- package/features/contentModel/CreateModelFrom/CreateModelFromRepository.js.map +1 -1
- package/features/contentModel/UpdateModel/UpdateModelRepository.js +8 -2
- package/features/contentModel/UpdateModel/UpdateModelRepository.js.map +1 -1
- package/features/contentModel/UpdateModel/UpdateModelUseCase.js +4 -1
- package/features/contentModel/UpdateModel/UpdateModelUseCase.js.map +1 -1
- package/features/modelBuilder/feature.js +2 -2
- package/features/modelBuilder/feature.js.map +1 -1
- package/features/modelBuilder/fields/BaseFieldBuilder.d.ts +36 -0
- package/features/modelBuilder/fields/BaseFieldBuilder.js +41 -0
- package/features/modelBuilder/fields/BaseFieldBuilder.js.map +1 -0
- package/features/modelBuilder/fields/DataFieldBuilder.d.ts +228 -0
- package/features/modelBuilder/fields/DataFieldBuilder.js +219 -0
- package/features/modelBuilder/fields/DataFieldBuilder.js.map +1 -0
- package/features/modelBuilder/fields/DynamicZoneFieldType.d.ts +2 -2
- package/features/modelBuilder/fields/DynamicZoneFieldType.js +6 -3
- package/features/modelBuilder/fields/DynamicZoneFieldType.js.map +1 -1
- package/features/modelBuilder/fields/FieldBuilder.d.ts +5 -228
- package/features/modelBuilder/fields/FieldBuilder.js +3 -231
- package/features/modelBuilder/fields/FieldBuilder.js.map +1 -1
- package/features/modelBuilder/fields/LayoutFieldBuilder.d.ts +7 -0
- package/features/modelBuilder/fields/LayoutFieldBuilder.js +9 -0
- package/features/modelBuilder/fields/LayoutFieldBuilder.js.map +1 -0
- package/features/modelBuilder/fields/ObjectFieldType.d.ts +4 -3
- package/features/modelBuilder/fields/ObjectFieldType.js +19 -4
- package/features/modelBuilder/fields/ObjectFieldType.js.map +1 -1
- package/features/modelBuilder/fields/UiAlertFieldType.d.ts +8 -4
- package/features/modelBuilder/fields/UiAlertFieldType.js +23 -6
- package/features/modelBuilder/fields/UiAlertFieldType.js.map +1 -1
- package/features/modelBuilder/fields/UiSeparatorFieldType.d.ts +6 -4
- package/features/modelBuilder/fields/UiSeparatorFieldType.js +18 -4
- package/features/modelBuilder/fields/UiSeparatorFieldType.js.map +1 -1
- package/features/modelBuilder/fields/UiTabsFieldType.d.ts +28 -0
- package/features/modelBuilder/fields/UiTabsFieldType.js +75 -0
- package/features/modelBuilder/fields/UiTabsFieldType.js.map +1 -0
- package/features/modelBuilder/fields/abstractions.d.ts +2 -2
- package/features/modelBuilder/fields/abstractions.js.map +1 -1
- package/features/modelBuilder/index.d.ts +2 -0
- package/features/modelBuilder/index.js +2 -0
- package/features/modelBuilder/index.js.map +1 -1
- package/features/modelBuilder/models/BaseModelBuilder.d.ts +8 -3
- package/features/modelBuilder/models/BaseModelBuilder.js +19 -0
- package/features/modelBuilder/models/BaseModelBuilder.js.map +1 -1
- package/features/modelBuilder/models/PrivateModelBuilder.js +4 -2
- package/features/modelBuilder/models/PrivateModelBuilder.js.map +1 -1
- package/features/modelBuilder/models/PublicModelBuilder.js +16 -11
- package/features/modelBuilder/models/PublicModelBuilder.js.map +1 -1
- package/graphql/schema/baseSchema.js +17 -15
- package/graphql/schema/baseSchema.js.map +1 -1
- package/graphql/schema/cms/helpers/index.d.ts +1 -0
- package/graphql/schema/cms/helpers/index.js +1 -0
- package/graphql/schema/cms/helpers/index.js.map +1 -1
- package/graphql/schema/cms/helpers/transformWhereToNested.d.ts +17 -0
- package/graphql/schema/cms/helpers/transformWhereToNested.js +54 -0
- package/graphql/schema/cms/helpers/transformWhereToNested.js.map +1 -0
- package/graphql/schema/cms/helpers.d.ts +1 -0
- package/graphql/schema/cms/helpers.js +1 -0
- package/graphql/schema/cms/helpers.js.map +1 -1
- package/graphql/schema/cms/listEntriesResolver.js +6 -2
- package/graphql/schema/cms/listEntriesResolver.js.map +1 -1
- package/graphql/schema/contentModels.js +21 -3
- package/graphql/schema/contentModels.js.map +1 -1
- package/graphql/schema/createManageSDL.js +4 -2
- package/graphql/schema/createManageSDL.js.map +1 -1
- package/graphqlFields/index.js +1 -2
- package/graphqlFields/index.js.map +1 -1
- package/package.json +22 -22
- package/plugins/CmsModelPlugin.js +19 -4
- package/plugins/CmsModelPlugin.js.map +1 -1
- package/types/fields/objectField.d.ts +2 -0
- package/types/fields/objectField.js.map +1 -1
- package/types/model.d.ts +32 -3
- package/types/model.js.map +1 -1
- package/types/modelField.d.ts +19 -3
- package/types/modelField.js.map +1 -1
- package/types/types.d.ts +12 -9
- package/types/types.js.map +1 -1
- package/utils/createModelField.js +4 -2
- package/utils/createModelField.js.map +1 -1
- package/crud/contentEntry/entryDataFactories/state.d.ts +0 -10
- package/crud/contentEntry/entryDataFactories/state.js +0 -16
- package/crud/contentEntry/entryDataFactories/state.js.map +0 -1
- package/features/modelBuilder/fields/UiFieldType.d.ts +0 -18
- package/features/modelBuilder/fields/UiFieldType.js +0 -25
- package/features/modelBuilder/fields/UiFieldType.js.map +0 -1
- package/graphqlFields/ui.d.ts +0 -2
- package/graphqlFields/ui.js +0 -32
- package/graphqlFields/ui.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["camelCase","Result","CreateModelRepository","RepositoryAbstraction","ModelCache","PluginModelsProvider","ListModelsUseCase","ModelAlreadyExistsError","ModelPersistenceError","ModelValidationError","StorageOperations","TenantContext","CmsContext","validateExistingModelId","validateModelIdAllowed","validateEndingAllowed","ensureTypeTag","validateSingularApiName","validatePluralApiName","validateModelFields","getModelId","model","modelId","name","value","trim","isModelIdValid","toLowerCase","CreateModelRepositoryImpl","constructor","modelCache","pluginModelsProvider","listModelsUseCase","storageOperations","tenantContext","cmsContext","execute","tenant","getTenant","error","fail","message","data","pluginModels","list","id","pluginModelConflict","find","pm","modelsResult","isFail","models","existingModel","context","tags","create","clear","ok","console","stack","createImplementation","implementation","dependencies"],"sources":["CreateModelRepository.ts"],"sourcesContent":["import camelCase from \"lodash/camelCase.js\";\nimport { Result } from \"@webiny/feature/api\";\nimport { CreateModelRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { ModelCache } from \"~/features/contentModel/shared/abstractions.js\";\nimport { PluginModelsProvider } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ListModelsUseCase } from \"~/features/contentModel/ListModels/index.js\";\nimport { ModelAlreadyExistsError } from \"~/domain/contentModel/errors.js\";\nimport { ModelPersistenceError } from \"~/domain/contentModel/errors.js\";\nimport { ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { StorageOperations } from \"~/features/shared/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport { CmsContext } from \"~/features/shared/abstractions.js\";\nimport {\n validateExistingModelId,\n validateModelIdAllowed\n} from \"~/crud/contentModel/validate/modelId.js\";\nimport { validateEndingAllowed } from \"~/crud/contentModel/validate/endingAllowed.js\";\nimport type { CmsModel } from \"~/types/index.js\";\nimport { ensureTypeTag } from \"~/domain/contentModel/ensureTypeTag.js\";\nimport { validateSingularApiName } from \"~/domain/contentModel/validation/singularApiName.js\";\nimport { validatePluralApiName } from \"~/domain/contentModel/validation/pluralApiName.js\";\nimport { validateModelFields } from \"~/domain/contentModel/validation/modelFields.js\";\n\n/**\n * Generate modelId from model following the exact logic from beforeCreate.ts\n */\nconst getModelId = (model: { modelId?: string; name?: string }): string => {\n const { modelId, name } = model;\n const value = modelId ? modelId.trim() : null;\n if (value) {\n const isModelIdValid = camelCase(value).toLowerCase() === value.toLowerCase();\n if (isModelIdValid) {\n return value;\n }\n return camelCase(value);\n } else if (name) {\n return camelCase(name.trim());\n }\n throw new ModelValidationError(\n `There is no \"modelId\" or \"name\" passed into the create model method.`\n );\n};\n\n/**\n * CreateModelRepository - Validates domain rules and persists a new model.\n *\n * Responsibilities:\n * - Generate modelId from input\n * - Validate modelId is allowed (not in disallowed list)\n * - Validate API name endings\n * - Validate modelId uniqueness (database + plugins)\n * - Validate API name uniqueness (database + plugins)\n * - Validate plugin conflicts\n * - Validate model fields\n * - Persist to storage\n * - Clear ModelCache after successful create\n */\nclass CreateModelRepositoryImpl implements RepositoryAbstraction.Interface {\n public constructor(\n private modelCache: ModelCache.Interface,\n private pluginModelsProvider: PluginModelsProvider.Interface,\n private listModelsUseCase: ListModelsUseCase.Interface,\n private storageOperations: StorageOperations.Interface,\n private tenantContext: TenantContext.Interface,\n private cmsContext: CmsContext.Interface\n ) {}\n\n async execute(model: CmsModel): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n const tenant = this.tenantContext.getTenant();\n\n // TODO: this will eventually become part of the Model domain object.\n const modelId = getModelId(model);\n model.modelId = modelId;\n\n // Validate modelId is allowed (not in disallowed list)\n try {\n validateModelIdAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({\n message: error.message,\n data: error.data\n })\n );\n }\n\n // Validate API name endings\n try {\n validateEndingAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({\n message: error.message,\n data: error.data\n })\n );\n }\n\n // Check for plugin model conflicts\n const pluginModels = await this.pluginModelsProvider.list(tenant.id);\n const pluginModelConflict = pluginModels.find(pm => {\n return pm.modelId === model.modelId;\n });\n\n if (pluginModelConflict) {\n return Result.fail(\n new ModelAlreadyExistsError({\n modelId,\n message: `Model \"${modelId}\" is already registered via a plugin.`\n })\n );\n }\n\n // Get all models for further validation\n const modelsResult = await this.listModelsUseCase.execute();\n\n if (modelsResult.isFail()) {\n return Result.fail(new ModelPersistenceError(modelsResult.error));\n }\n\n const models = modelsResult.value;\n\n try {\n /**\n * We need to check for the existence of:\n * - modelId\n * - singularApiName\n * - pluralApiName\n */\n for (const existingModel of models) {\n validateExistingModelId({\n existingModel,\n model\n });\n validateSingularApiName({\n existingModel,\n model\n });\n validatePluralApiName({\n existingModel,\n model\n });\n }\n\n await validateModelFields({\n models,\n model,\n context: this.cmsContext\n });\n } catch (error) {\n return Result.fail(new ModelValidationError((error as Error).message));\n }\n\n // TODO: ideally, this will eventually be handled by the Model domain object\n model.tags = ensureTypeTag(model);\n\n // Persist to storage\n await this.storageOperations.models.create({ model });\n\n // Clear cache\n this.modelCache.clear();\n\n return Result.ok();\n } catch (error) {\n console.error(error, error.stack);\n return Result.fail(new ModelPersistenceError(error as Error));\n }\n }\n}\n\nexport const CreateModelRepository = RepositoryAbstraction.createImplementation({\n implementation: CreateModelRepositoryImpl,\n dependencies: [\n ModelCache,\n PluginModelsProvider,\n ListModelsUseCase,\n StorageOperations,\n TenantContext,\n CmsContext\n ]\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["camelCase","Result","CreateModelRepository","RepositoryAbstraction","ModelCache","PluginModelsProvider","ListModelsUseCase","ModelAlreadyExistsError","ModelPersistenceError","ModelValidationError","StorageOperations","TenantContext","CmsContext","validateExistingModelId","validateModelIdAllowed","validateEndingAllowed","ensureTypeTag","validateSingularApiName","validatePluralApiName","validateModelFields","getModelId","model","modelId","name","value","trim","isModelIdValid","toLowerCase","CreateModelRepositoryImpl","constructor","modelCache","pluginModelsProvider","listModelsUseCase","storageOperations","tenantContext","cmsContext","execute","tenant","getTenant","error","fail","message","data","pluginModels","list","id","pluginModelConflict","find","pm","modelsResult","isFail","models","existingModel","context","tags","create","clear","ok","console","stack","createImplementation","implementation","dependencies"],"sources":["CreateModelRepository.ts"],"sourcesContent":["import camelCase from \"lodash/camelCase.js\";\nimport { Result } from \"@webiny/feature/api\";\nimport { CreateModelRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { ModelCache } from \"~/features/contentModel/shared/abstractions.js\";\nimport { PluginModelsProvider } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ListModelsUseCase } from \"~/features/contentModel/ListModels/index.js\";\nimport { ModelAlreadyExistsError } from \"~/domain/contentModel/errors.js\";\nimport { ModelPersistenceError } from \"~/domain/contentModel/errors.js\";\nimport { ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { StorageOperations } from \"~/features/shared/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport { CmsContext } from \"~/features/shared/abstractions.js\";\nimport {\n validateExistingModelId,\n validateModelIdAllowed\n} from \"~/crud/contentModel/validate/modelId.js\";\nimport { validateEndingAllowed } from \"~/crud/contentModel/validate/endingAllowed.js\";\nimport type { CmsModel } from \"~/types/index.js\";\nimport { ensureTypeTag } from \"~/domain/contentModel/ensureTypeTag.js\";\nimport { validateSingularApiName } from \"~/domain/contentModel/validation/singularApiName.js\";\nimport { validatePluralApiName } from \"~/domain/contentModel/validation/pluralApiName.js\";\nimport { validateModelFields } from \"~/domain/contentModel/validation/modelFields.js\";\n\n/**\n * Generate modelId from model following the exact logic from beforeCreate.ts\n */\nconst getModelId = (model: { modelId?: string; name?: string }): string => {\n const { modelId, name } = model;\n const value = modelId ? modelId.trim() : null;\n if (value) {\n const isModelIdValid = camelCase(value).toLowerCase() === value.toLowerCase();\n if (isModelIdValid) {\n return value;\n }\n return camelCase(value);\n } else if (name) {\n return camelCase(name.trim());\n }\n throw new ModelValidationError(\n `There is no \"modelId\" or \"name\" passed into the create model method.`\n );\n};\n\n/**\n * CreateModelRepository - Validates domain rules and persists a new model.\n *\n * Responsibilities:\n * - Generate modelId from input\n * - Validate modelId is allowed (not in disallowed list)\n * - Validate API name endings\n * - Validate modelId uniqueness (database + plugins)\n * - Validate API name uniqueness (database + plugins)\n * - Validate plugin conflicts\n * - Validate model fields\n * - Persist to storage\n * - Clear ModelCache after successful create\n */\nclass CreateModelRepositoryImpl implements RepositoryAbstraction.Interface {\n public constructor(\n private modelCache: ModelCache.Interface,\n private pluginModelsProvider: PluginModelsProvider.Interface,\n private listModelsUseCase: ListModelsUseCase.Interface,\n private storageOperations: StorageOperations.Interface,\n private tenantContext: TenantContext.Interface,\n private cmsContext: CmsContext.Interface\n ) {}\n\n async execute(model: CmsModel): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n const tenant = this.tenantContext.getTenant();\n\n // TODO: this will eventually become part of the Model domain object.\n const modelId = getModelId(model);\n model.modelId = modelId;\n\n // Validate modelId is allowed (not in disallowed list)\n try {\n validateModelIdAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({\n message: error.message,\n data: error.data\n })\n );\n }\n\n // Validate API name endings\n try {\n validateEndingAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({\n message: error.message,\n data: error.data\n })\n );\n }\n\n // Check for plugin model conflicts\n const pluginModels = await this.pluginModelsProvider.list(tenant.id);\n const pluginModelConflict = pluginModels.find(pm => {\n return pm.modelId === model.modelId;\n });\n\n if (pluginModelConflict) {\n return Result.fail(\n new ModelAlreadyExistsError({\n modelId,\n message: `Model \"${modelId}\" is already registered via a plugin.`\n })\n );\n }\n\n // Get all models for further validation\n const modelsResult = await this.listModelsUseCase.execute();\n\n if (modelsResult.isFail()) {\n return Result.fail(new ModelPersistenceError(modelsResult.error));\n }\n\n const models = modelsResult.value;\n\n try {\n /**\n * We need to check for the existence of:\n * - modelId\n * - singularApiName\n * - pluralApiName\n */\n for (const existingModel of models) {\n validateExistingModelId({\n existingModel,\n model\n });\n validateSingularApiName({\n existingModel,\n model\n });\n validatePluralApiName({\n existingModel,\n model\n });\n }\n\n await validateModelFields({\n models,\n model,\n context: this.cmsContext\n });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({ message: error.message, data: error.data })\n );\n }\n\n // TODO: ideally, this will eventually be handled by the Model domain object\n model.tags = ensureTypeTag(model);\n\n // Persist to storage\n await this.storageOperations.models.create({ model });\n\n // Clear cache\n this.modelCache.clear();\n\n return Result.ok();\n } catch (error) {\n console.error(error, error.stack);\n return Result.fail(new ModelPersistenceError(error as Error));\n }\n }\n}\n\nexport const CreateModelRepository = RepositoryAbstraction.createImplementation({\n implementation: CreateModelRepositoryImpl,\n dependencies: [\n ModelCache,\n PluginModelsProvider,\n ListModelsUseCase,\n StorageOperations,\n TenantContext,\n CmsContext\n ]\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -75,7 +75,10 @@ class CreateModelFromRepositoryImpl {
|
|
|
75
75
|
model
|
|
76
76
|
});
|
|
77
77
|
} catch (error) {
|
|
78
|
-
return Result.fail(new ModelValidationError(
|
|
78
|
+
return Result.fail(new ModelValidationError({
|
|
79
|
+
message: error.message,
|
|
80
|
+
data: error.data
|
|
81
|
+
}));
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
// Validate API name endings
|
|
@@ -84,7 +87,10 @@ class CreateModelFromRepositoryImpl {
|
|
|
84
87
|
model
|
|
85
88
|
});
|
|
86
89
|
} catch (error) {
|
|
87
|
-
return Result.fail(new ModelValidationError(
|
|
90
|
+
return Result.fail(new ModelValidationError({
|
|
91
|
+
message: error.message,
|
|
92
|
+
data: error.data
|
|
93
|
+
}));
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
// Validate modelId uniqueness (database)
|
|
@@ -135,7 +141,10 @@ class CreateModelFromRepositoryImpl {
|
|
|
135
141
|
context: this.cmsContext
|
|
136
142
|
});
|
|
137
143
|
} catch (error) {
|
|
138
|
-
return Result.fail(new ModelValidationError(
|
|
144
|
+
return Result.fail(new ModelValidationError({
|
|
145
|
+
message: error.message,
|
|
146
|
+
data: error.data
|
|
147
|
+
}));
|
|
139
148
|
}
|
|
140
149
|
|
|
141
150
|
// Ensure type tags
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["camelCase","Result","CreateModelFromRepository","RepositoryAbstraction","ModelCache","PluginModelsProvider","ModelsFetcher","ModelAlreadyExistsError","ModelPersistenceError","ModelValidationError","StorageOperations","TenantContext","CmsContext","validateExistingModelId","validateModelIdAllowed","validateEndingAllowed","validateSingularApiName","validatePluralApiName","validateModelFields","ensureTypeTag","getModelId","model","modelId","name","value","trim","isModelIdValid","toLowerCase","CreateModelFromRepositoryImpl","constructor","modelCache","pluginModelsProvider","modelsFetcher","storageOperations","tenantContext","cmsContext","execute","tenant","getTenant","error","fail","message","modelsResult","fetchAll","isFail","existingModel","find","m","pluginModels","list","id","pluginModelConflict","pm","singularApiName","pluralApiName","models","context","tags","create","clear","ok","createImplementation","implementation","dependencies"],"sources":["CreateModelFromRepository.ts"],"sourcesContent":["import camelCase from \"lodash/camelCase.js\";\nimport { Result } from \"@webiny/feature/api\";\nimport { CreateModelFromRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { ModelCache } from \"~/features/contentModel/shared/abstractions.js\";\nimport { PluginModelsProvider } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelsFetcher } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelAlreadyExistsError } from \"~/domain/contentModel/errors.js\";\nimport { ModelPersistenceError } from \"~/domain/contentModel/errors.js\";\nimport { ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { StorageOperations } from \"~/features/shared/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport { CmsContext } from \"~/features/shared/abstractions.js\";\nimport {\n validateExistingModelId,\n validateModelIdAllowed\n} from \"~/crud/contentModel/validate/modelId.js\";\nimport { validateEndingAllowed } from \"~/crud/contentModel/validate/endingAllowed.js\";\nimport { validateSingularApiName } from \"~/domain/contentModel/validation/singularApiName.js\";\nimport { validatePluralApiName } from \"~/domain/contentModel/validation/pluralApiName.js\";\nimport { validateModelFields } from \"~/domain/contentModel/validation/modelFields.js\";\nimport type { CmsModel } from \"~/types/index.js\";\nimport { ensureTypeTag } from \"~/domain/contentModel/ensureTypeTag.js\";\n\n/**\n * Generate modelId from model following the exact logic from beforeCreate.ts\n */\nconst getModelId = (model: { modelId?: string; name?: string }): string => {\n const { modelId, name } = model;\n const value = modelId ? modelId.trim() : null;\n if (value) {\n const isModelIdValid = camelCase(value).toLowerCase() === value.toLowerCase();\n if (isModelIdValid) {\n return value;\n }\n return camelCase(value);\n } else if (name) {\n return camelCase(name.trim());\n }\n throw new ModelValidationError(\n `There is no \"modelId\" or \"name\" passed into the create model from method.`\n );\n};\n\n/**\n * CreateModelFromRepository - Validates domain rules and persists cloned model.\n *\n * Responsibilities:\n * - Generate modelId from input\n * - Validate modelId is allowed (not in disallowed list)\n * - Validate API name endings\n * - Validate modelId uniqueness (database + plugins)\n * - Validate API name uniqueness (database + plugins)\n * - Validate plugin conflicts\n * - Validate model fields\n * - Persist to storage\n * - Clear ModelCache after successful create\n */\nclass CreateModelFromRepositoryImpl implements RepositoryAbstraction.Interface {\n public constructor(\n private modelCache: ModelCache.Interface,\n private pluginModelsProvider: PluginModelsProvider.Interface,\n private modelsFetcher: ModelsFetcher.Interface,\n private storageOperations: StorageOperations.Interface,\n private tenantContext: TenantContext.Interface,\n private cmsContext: CmsContext.Interface\n ) {}\n\n async execute(model: CmsModel): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n const tenant = this.tenantContext.getTenant();\n\n // Generate modelId using the exact logic from beforeCreate.ts\n const modelId = getModelId(model);\n model.modelId = modelId;\n\n // Validate modelId is allowed (not in disallowed list)\n try {\n validateModelIdAllowed({ model });\n } catch (error) {\n return Result.fail(new ModelValidationError((error as Error).message));\n }\n\n // Validate API name endings\n try {\n validateEndingAllowed({ model });\n } catch (error) {\n return Result.fail(new ModelValidationError((error as Error).message));\n }\n\n // Validate modelId uniqueness (database)\n const modelsResult = await this.modelsFetcher.fetchAll();\n if (modelsResult.isFail()) {\n return Result.fail(new ModelPersistenceError(modelsResult.error));\n }\n\n const existingModel = modelsResult.value.find(m => m.modelId === modelId);\n if (existingModel) {\n return Result.fail(new ModelAlreadyExistsError({ modelId }));\n }\n\n // Check for plugin model conflicts\n const pluginModels = await this.pluginModelsProvider.list(tenant.id);\n const pluginModelConflict = pluginModels.find(pm => {\n return (\n pm.modelId === model.modelId ||\n pm.singularApiName === model.singularApiName ||\n pm.pluralApiName === model.pluralApiName\n );\n });\n\n if (pluginModelConflict) {\n return Result.fail(\n new ModelAlreadyExistsError({\n modelId,\n message: `Model \"${modelId}\" is already registered via a plugin.`\n })\n );\n }\n\n const models = modelsResult.value;\n\n try {\n // Validate uniqueness\n for (const existingModel of models) {\n validateExistingModelId({\n existingModel,\n model\n });\n validateSingularApiName({\n existingModel,\n model\n });\n validatePluralApiName({\n existingModel,\n model\n });\n }\n\n // Validate model fields\n await validateModelFields({\n models,\n model,\n context: this.cmsContext\n });\n } catch (error) {\n return Result.fail(new ModelValidationError((error as Error).message));\n }\n\n // Ensure type tags\n model.tags = ensureTypeTag(model);\n\n // Persist to storage\n await this.storageOperations.models.create({ model });\n\n // Clear cache\n this.modelCache.clear();\n\n return Result.ok();\n } catch (error) {\n return Result.fail(new ModelPersistenceError(error as Error));\n }\n }\n}\n\nexport const CreateModelFromRepository = RepositoryAbstraction.createImplementation({\n implementation: CreateModelFromRepositoryImpl,\n dependencies: [\n ModelCache,\n PluginModelsProvider,\n ModelsFetcher,\n StorageOperations,\n TenantContext,\n CmsContext\n ]\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["camelCase","Result","CreateModelFromRepository","RepositoryAbstraction","ModelCache","PluginModelsProvider","ModelsFetcher","ModelAlreadyExistsError","ModelPersistenceError","ModelValidationError","StorageOperations","TenantContext","CmsContext","validateExistingModelId","validateModelIdAllowed","validateEndingAllowed","validateSingularApiName","validatePluralApiName","validateModelFields","ensureTypeTag","getModelId","model","modelId","name","value","trim","isModelIdValid","toLowerCase","CreateModelFromRepositoryImpl","constructor","modelCache","pluginModelsProvider","modelsFetcher","storageOperations","tenantContext","cmsContext","execute","tenant","getTenant","error","fail","message","data","modelsResult","fetchAll","isFail","existingModel","find","m","pluginModels","list","id","pluginModelConflict","pm","singularApiName","pluralApiName","models","context","tags","create","clear","ok","createImplementation","implementation","dependencies"],"sources":["CreateModelFromRepository.ts"],"sourcesContent":["import camelCase from \"lodash/camelCase.js\";\nimport { Result } from \"@webiny/feature/api\";\nimport { CreateModelFromRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { ModelCache } from \"~/features/contentModel/shared/abstractions.js\";\nimport { PluginModelsProvider } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelsFetcher } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelAlreadyExistsError } from \"~/domain/contentModel/errors.js\";\nimport { ModelPersistenceError } from \"~/domain/contentModel/errors.js\";\nimport { ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { StorageOperations } from \"~/features/shared/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport { CmsContext } from \"~/features/shared/abstractions.js\";\nimport {\n validateExistingModelId,\n validateModelIdAllowed\n} from \"~/crud/contentModel/validate/modelId.js\";\nimport { validateEndingAllowed } from \"~/crud/contentModel/validate/endingAllowed.js\";\nimport { validateSingularApiName } from \"~/domain/contentModel/validation/singularApiName.js\";\nimport { validatePluralApiName } from \"~/domain/contentModel/validation/pluralApiName.js\";\nimport { validateModelFields } from \"~/domain/contentModel/validation/modelFields.js\";\nimport type { CmsModel } from \"~/types/index.js\";\nimport { ensureTypeTag } from \"~/domain/contentModel/ensureTypeTag.js\";\n\n/**\n * Generate modelId from model following the exact logic from beforeCreate.ts\n */\nconst getModelId = (model: { modelId?: string; name?: string }): string => {\n const { modelId, name } = model;\n const value = modelId ? modelId.trim() : null;\n if (value) {\n const isModelIdValid = camelCase(value).toLowerCase() === value.toLowerCase();\n if (isModelIdValid) {\n return value;\n }\n return camelCase(value);\n } else if (name) {\n return camelCase(name.trim());\n }\n throw new ModelValidationError(\n `There is no \"modelId\" or \"name\" passed into the create model from method.`\n );\n};\n\n/**\n * CreateModelFromRepository - Validates domain rules and persists cloned model.\n *\n * Responsibilities:\n * - Generate modelId from input\n * - Validate modelId is allowed (not in disallowed list)\n * - Validate API name endings\n * - Validate modelId uniqueness (database + plugins)\n * - Validate API name uniqueness (database + plugins)\n * - Validate plugin conflicts\n * - Validate model fields\n * - Persist to storage\n * - Clear ModelCache after successful create\n */\nclass CreateModelFromRepositoryImpl implements RepositoryAbstraction.Interface {\n public constructor(\n private modelCache: ModelCache.Interface,\n private pluginModelsProvider: PluginModelsProvider.Interface,\n private modelsFetcher: ModelsFetcher.Interface,\n private storageOperations: StorageOperations.Interface,\n private tenantContext: TenantContext.Interface,\n private cmsContext: CmsContext.Interface\n ) {}\n\n async execute(model: CmsModel): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n const tenant = this.tenantContext.getTenant();\n\n // Generate modelId using the exact logic from beforeCreate.ts\n const modelId = getModelId(model);\n model.modelId = modelId;\n\n // Validate modelId is allowed (not in disallowed list)\n try {\n validateModelIdAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({ message: error.message, data: error.data })\n );\n }\n\n // Validate API name endings\n try {\n validateEndingAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({ message: error.message, data: error.data })\n );\n }\n\n // Validate modelId uniqueness (database)\n const modelsResult = await this.modelsFetcher.fetchAll();\n if (modelsResult.isFail()) {\n return Result.fail(new ModelPersistenceError(modelsResult.error));\n }\n\n const existingModel = modelsResult.value.find(m => m.modelId === modelId);\n if (existingModel) {\n return Result.fail(new ModelAlreadyExistsError({ modelId }));\n }\n\n // Check for plugin model conflicts\n const pluginModels = await this.pluginModelsProvider.list(tenant.id);\n const pluginModelConflict = pluginModels.find(pm => {\n return (\n pm.modelId === model.modelId ||\n pm.singularApiName === model.singularApiName ||\n pm.pluralApiName === model.pluralApiName\n );\n });\n\n if (pluginModelConflict) {\n return Result.fail(\n new ModelAlreadyExistsError({\n modelId,\n message: `Model \"${modelId}\" is already registered via a plugin.`\n })\n );\n }\n\n const models = modelsResult.value;\n\n try {\n // Validate uniqueness\n for (const existingModel of models) {\n validateExistingModelId({\n existingModel,\n model\n });\n validateSingularApiName({\n existingModel,\n model\n });\n validatePluralApiName({\n existingModel,\n model\n });\n }\n\n // Validate model fields\n await validateModelFields({\n models,\n model,\n context: this.cmsContext\n });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({ message: error.message, data: error.data })\n );\n }\n\n // Ensure type tags\n model.tags = ensureTypeTag(model);\n\n // Persist to storage\n await this.storageOperations.models.create({ model });\n\n // Clear cache\n this.modelCache.clear();\n\n return Result.ok();\n } catch (error) {\n return Result.fail(new ModelPersistenceError(error as Error));\n }\n }\n}\n\nexport const CreateModelFromRepository = RepositoryAbstraction.createImplementation({\n implementation: CreateModelFromRepositoryImpl,\n dependencies: [\n ModelCache,\n PluginModelsProvider,\n ModelsFetcher,\n StorageOperations,\n TenantContext,\n CmsContext\n ]\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -37,7 +37,10 @@ class UpdateModelRepositoryImpl {
|
|
|
37
37
|
model
|
|
38
38
|
});
|
|
39
39
|
} catch (error) {
|
|
40
|
-
return Result.fail(new ModelValidationError(
|
|
40
|
+
return Result.fail(new ModelValidationError({
|
|
41
|
+
message: error.message,
|
|
42
|
+
data: error.data
|
|
43
|
+
}));
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
// Get all models for validation (excluding the current model)
|
|
@@ -80,7 +83,10 @@ class UpdateModelRepositoryImpl {
|
|
|
80
83
|
context: this.cmsContext
|
|
81
84
|
});
|
|
82
85
|
} catch (error) {
|
|
83
|
-
return Result.fail(new ModelValidationError(
|
|
86
|
+
return Result.fail(new ModelValidationError({
|
|
87
|
+
message: error.message,
|
|
88
|
+
data: error.data
|
|
89
|
+
}));
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
// Persist to storage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Result","UpdateModelRepository","RepositoryAbstraction","ModelCache","ModelsFetcher","ModelCannotUpdateCodeModelError","ModelPersistenceError","ModelValidationError","StorageOperations","CmsContext","validateEndingAllowed","validateSingularApiName","validatePluralApiName","validateModelFields","UpdateModelRepositoryImpl","constructor","modelCache","modelsFetcher","storageOperations","cmsContext","execute","model","original","error","fail","message","modelsResult","security","withoutAuthorization","fetchAll","isFail","allModels","value","models","filter","m","modelId","existingModelResult","fetchById","isPlugin","existingModel","context","update","clear","ok","createImplementation","implementation","dependencies"],"sources":["UpdateModelRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UpdateModelRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { ModelCache } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelsFetcher } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelCannotUpdateCodeModelError } from \"~/domain/contentModel/errors.js\";\nimport { ModelPersistenceError } from \"~/domain/contentModel/errors.js\";\nimport { ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { StorageOperations } from \"~/features/shared/abstractions.js\";\nimport { CmsContext } from \"~/features/shared/abstractions.js\";\nimport { validateEndingAllowed } from \"~/crud/contentModel/validate/endingAllowed.js\";\nimport { validateSingularApiName } from \"~/domain/contentModel/validation/singularApiName.js\";\nimport { validatePluralApiName } from \"~/domain/contentModel/validation/pluralApiName.js\";\nimport { validateModelFields } from \"~/domain/contentModel/validation/modelFields.js\";\nimport type { CmsModel } from \"~/types/index.js\";\n\n/**\n * UpdateModelRepository - Validates domain rules and persists model updates.\n *\n * Responsibilities:\n * - Validate API name endings\n * - Validate singularApiName uniqueness (excluding current model)\n * - Validate pluralApiName uniqueness (excluding current model)\n * - Validate model fields\n * - Persist to storage\n * - Clear ModelCache after successful update\n */\nclass UpdateModelRepositoryImpl implements RepositoryAbstraction.Interface {\n public constructor(\n private modelCache: ModelCache.Interface,\n private modelsFetcher: ModelsFetcher.Interface,\n private storageOperations: StorageOperations.Interface,\n private cmsContext: CmsContext.Interface\n ) {}\n\n async execute(\n model: CmsModel,\n original: CmsModel\n ): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n // Validate API name endings\n try {\n validateEndingAllowed({ model });\n } catch (error) {\n return Result.fail(new ModelValidationError(
|
|
1
|
+
{"version":3,"names":["Result","UpdateModelRepository","RepositoryAbstraction","ModelCache","ModelsFetcher","ModelCannotUpdateCodeModelError","ModelPersistenceError","ModelValidationError","StorageOperations","CmsContext","validateEndingAllowed","validateSingularApiName","validatePluralApiName","validateModelFields","UpdateModelRepositoryImpl","constructor","modelCache","modelsFetcher","storageOperations","cmsContext","execute","model","original","error","fail","message","data","modelsResult","security","withoutAuthorization","fetchAll","isFail","allModels","value","models","filter","m","modelId","existingModelResult","fetchById","isPlugin","existingModel","context","update","clear","ok","createImplementation","implementation","dependencies"],"sources":["UpdateModelRepository.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UpdateModelRepository as RepositoryAbstraction } from \"./abstractions.js\";\nimport { ModelCache } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelsFetcher } from \"~/features/contentModel/shared/abstractions.js\";\nimport { ModelCannotUpdateCodeModelError } from \"~/domain/contentModel/errors.js\";\nimport { ModelPersistenceError } from \"~/domain/contentModel/errors.js\";\nimport { ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { StorageOperations } from \"~/features/shared/abstractions.js\";\nimport { CmsContext } from \"~/features/shared/abstractions.js\";\nimport { validateEndingAllowed } from \"~/crud/contentModel/validate/endingAllowed.js\";\nimport { validateSingularApiName } from \"~/domain/contentModel/validation/singularApiName.js\";\nimport { validatePluralApiName } from \"~/domain/contentModel/validation/pluralApiName.js\";\nimport { validateModelFields } from \"~/domain/contentModel/validation/modelFields.js\";\nimport type { CmsModel } from \"~/types/index.js\";\n\n/**\n * UpdateModelRepository - Validates domain rules and persists model updates.\n *\n * Responsibilities:\n * - Validate API name endings\n * - Validate singularApiName uniqueness (excluding current model)\n * - Validate pluralApiName uniqueness (excluding current model)\n * - Validate model fields\n * - Persist to storage\n * - Clear ModelCache after successful update\n */\nclass UpdateModelRepositoryImpl implements RepositoryAbstraction.Interface {\n public constructor(\n private modelCache: ModelCache.Interface,\n private modelsFetcher: ModelsFetcher.Interface,\n private storageOperations: StorageOperations.Interface,\n private cmsContext: CmsContext.Interface\n ) {}\n\n async execute(\n model: CmsModel,\n original: CmsModel\n ): Promise<Result<void, RepositoryAbstraction.Error>> {\n try {\n // Validate API name endings\n try {\n validateEndingAllowed({ model });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({ message: error.message, data: error.data })\n );\n }\n\n // Get all models for validation (excluding the current model)\n const modelsResult = await this.cmsContext.security.withoutAuthorization(async () => {\n return await this.modelsFetcher.fetchAll();\n });\n\n if (modelsResult.isFail()) {\n return Result.fail(new ModelPersistenceError(modelsResult.error));\n }\n\n const allModels = modelsResult.value;\n const models = allModels.filter(m => m.modelId !== model.modelId);\n\n // Check if this is a plugin model\n const existingModelResult = await this.modelsFetcher.fetchById(model.modelId);\n if (existingModelResult.isFail()) {\n return Result.fail(new ModelPersistenceError(existingModelResult.error));\n }\n\n if (existingModelResult.value.isPlugin) {\n return Result.fail(new ModelCannotUpdateCodeModelError(model.modelId));\n }\n\n // Validate uniqueness\n try {\n for (const existingModel of models) {\n validateSingularApiName({\n existingModel,\n model\n });\n validatePluralApiName({\n existingModel,\n model\n });\n }\n\n // Validate model fields\n await validateModelFields({\n models,\n model,\n original,\n context: this.cmsContext\n });\n } catch (error) {\n return Result.fail(\n new ModelValidationError({ message: error.message, data: error.data })\n );\n }\n\n // Persist to storage\n await this.storageOperations.models.update({ model });\n\n // Clear cache\n this.modelCache.clear();\n\n return Result.ok();\n } catch (error) {\n return Result.fail(new ModelPersistenceError(error as Error));\n }\n }\n}\n\nexport const UpdateModelRepository = RepositoryAbstraction.createImplementation({\n implementation: UpdateModelRepositoryImpl,\n dependencies: [ModelCache, ModelsFetcher, StorageOperations, CmsContext]\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -58,7 +58,10 @@ class UpdateModelUseCaseImpl {
|
|
|
58
58
|
const validationResult = await createModelUpdateValidation().safeParseAsync(input);
|
|
59
59
|
if (!validationResult.success) {
|
|
60
60
|
const zodError = createZodError(validationResult.error);
|
|
61
|
-
return Result.fail(new ModelValidationError(
|
|
61
|
+
return Result.fail(new ModelValidationError({
|
|
62
|
+
message: zodError.message,
|
|
63
|
+
data: zodError.data
|
|
64
|
+
}));
|
|
62
65
|
}
|
|
63
66
|
const data = removeUndefinedValues(validationResult.data);
|
|
64
67
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Result","UpdateModelUseCase","UseCaseAbstraction","UpdateModelRepository","EventPublisher","ModelBeforeUpdateEvent","ModelAfterUpdateEvent","ModelUpdateErrorEvent","AccessControl","TenantContext","ModelNotAuthorizedError","ModelValidationError","createZodError","removeUndefinedValues","createModelUpdateValidation","ensureTypeTag","GetModelUseCase","UpdateModelUseCaseImpl","constructor","getModelUseCase","eventPublisher","repository","accessControl","tenantContext","execute","modelId","input","canAccess","canAccessModel","rwd","fail","getResult","isFail","original","structuredClone","value","validationResult","safeParseAsync","success","zodError","error","message","data","Object","keys","length","ok","tenant","getTenant","model","icon","titleFieldId","undefined","descriptionFieldId","imageFieldId","description","id","savedOn","Date","toISOString","fromModel","tags","publish","result","createImplementation","implementation","dependencies"],"sources":["UpdateModelUseCase.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UpdateModelUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport { UpdateModelRepository } from \"./abstractions.js\";\nimport { EventPublisher } from \"@webiny/api-core/features/EventPublisher\";\nimport { ModelBeforeUpdateEvent } from \"./events.js\";\nimport { ModelAfterUpdateEvent } from \"./events.js\";\nimport { ModelUpdateErrorEvent } from \"./events.js\";\nimport { AccessControl } from \"~/features/shared/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport { ModelNotAuthorizedError, ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { createZodError } from \"@webiny/utils\";\nimport { removeUndefinedValues } from \"@webiny/utils\";\nimport { createModelUpdateValidation } from \"~/domain/contentModel/schemas.js\";\nimport { ensureTypeTag } from \"~/domain/contentModel/ensureTypeTag.js\";\nimport type { CmsModel } from \"~/types/index.js\";\nimport type { CmsModelUpdateInput } from \"~/types/index.js\";\nimport { GetModelUseCase } from \"~/features/contentModel/GetModel/index.js\";\n\n/**\n * UpdateModelUseCase - Core model update orchestration.\n *\n * Responsibilities:\n * - Validate input (Zod)\n * - Fetch original model\n * - Create updated domain model object\n * - Handle group changes\n * - Handle field ID changes (title, description, image)\n * - Access control checks\n * - Publish before event\n * - Delegate to repository for validation and persistence\n * - Publish after event or error event\n *\n * Note: Repository handles domain validations (API name uniqueness, field validation, etc.)\n */\nclass UpdateModelUseCaseImpl implements UseCaseAbstraction.Interface {\n public constructor(\n private getModelUseCase: GetModelUseCase.Interface,\n private eventPublisher: EventPublisher.Interface,\n private repository: UpdateModelRepository.Interface,\n private accessControl: AccessControl.Interface,\n private tenantContext: TenantContext.Interface\n ) {}\n\n async execute(\n modelId: string,\n input: CmsModelUpdateInput\n ): Promise<Result<CmsModel, UseCaseAbstraction.Error>> {\n // Initial access control check\n const canAccess = await this.accessControl.canAccessModel({ rwd: \"w\" });\n if (!canAccess) {\n return Result.fail(new ModelNotAuthorizedError());\n }\n\n // Get the original model (with access control check)\n const getResult = await this.getModelUseCase.execute(modelId);\n if (getResult.isFail()) {\n return getResult;\n }\n\n const original = structuredClone(getResult.value);\n\n // Validate input\n const validationResult = await createModelUpdateValidation().safeParseAsync(input);\n if (!validationResult.success) {\n const zodError = createZodError(validationResult.error);\n return Result.fail(new ModelValidationError(zodError.message));\n }\n\n const data = removeUndefinedValues(validationResult.data);\n\n // If no changes, return original\n if (Object.keys(data).length === 0) {\n return Result.ok(original);\n }\n\n // Create updated model\n const tenant = this.tenantContext.getTenant();\n\n const model: CmsModel = {\n ...original,\n ...data,\n icon: data.icon ?? original.icon,\n // Handle optional field IDs explicitly\n titleFieldId:\n data.titleFieldId === undefined\n ? original.titleFieldId\n : (data.titleFieldId as string),\n descriptionFieldId:\n data.descriptionFieldId === undefined\n ? original.descriptionFieldId\n : data.descriptionFieldId,\n imageFieldId:\n data.imageFieldId === undefined ? original.imageFieldId : data.imageFieldId,\n description: data.description || original.description,\n tenant: original.tenant || tenant.id,\n savedOn: new Date().toISOString()\n };\n\n // Access control check on the updated model\n const canAccessModel = await this.accessControl.canAccessModel({ model, rwd: \"w\" });\n if (!canAccessModel) {\n return Result.fail(ModelNotAuthorizedError.fromModel(model));\n }\n\n // Ensure type tags\n model.tags = ensureTypeTag(model);\n\n // Publish before event\n await this.eventPublisher.publish(\n new ModelBeforeUpdateEvent({ model, original, input: data })\n );\n\n // Persist via repository (repository will validate)\n const result = await this.repository.execute(model, original);\n if (result.isFail()) {\n // Publish error event\n await this.eventPublisher.publish(\n new ModelUpdateErrorEvent({\n input: data,\n model,\n original,\n error: result.error\n })\n );\n return Result.fail(result.error);\n }\n\n // Publish after event\n await this.eventPublisher.publish(new ModelAfterUpdateEvent({ model, original }));\n\n return Result.ok(model);\n }\n}\n\nexport const UpdateModelUseCase = UseCaseAbstraction.createImplementation({\n implementation: UpdateModelUseCaseImpl,\n dependencies: [\n GetModelUseCase,\n EventPublisher,\n UpdateModelRepository,\n AccessControl,\n TenantContext\n ]\n});\n"],"mappings":"AAAA,SAASA,MAAM,QAAQ,qBAAqB;AAC5C,SAASC,kBAAkB,IAAIC,kBAAkB;AACjD,SAASC,qBAAqB;AAC9B,SAASC,cAAc,QAAQ,0CAA0C;AACzE,SAASC,sBAAsB;AAC/B,SAASC,qBAAqB;AAC9B,SAASC,qBAAqB;AAC9B,SAASC,aAAa;AACtB,SAASC,aAAa,QAAQ,yCAAyC;AACvE,SAASC,uBAAuB,EAAEC,oBAAoB;AACtD,SAASC,cAAc,QAAQ,eAAe;AAC9C,SAASC,qBAAqB,QAAQ,eAAe;AACrD,SAASC,2BAA2B;AACpC,SAASC,aAAa;AAGtB,SAASC,eAAe;;AAExB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,sBAAsB,CAAyC;EAC1DC,WAAWA,CACNC,eAA0C,EAC1CC,cAAwC,EACxCC,UAA2C,EAC3CC,aAAsC,EACtCC,aAAsC,EAChD;IAAA,KALUJ,eAA0C,GAA1CA,eAA0C;IAAA,KAC1CC,cAAwC,GAAxCA,cAAwC;IAAA,KACxCC,UAA2C,GAA3CA,UAA2C;IAAA,KAC3CC,aAAsC,GAAtCA,aAAsC;IAAA,KACtCC,aAAsC,GAAtCA,aAAsC;EAC/C;EAEH,MAAMC,OAAOA,CACTC,OAAe,EACfC,KAA0B,EACyB;IACnD;IACA,MAAMC,SAAS,GAAG,MAAM,IAAI,CAACL,aAAa,CAACM,cAAc,CAAC;MAAEC,GAAG,EAAE;IAAI,CAAC,CAAC;IACvE,IAAI,CAACF,SAAS,EAAE;MACZ,OAAO3B,MAAM,CAAC8B,IAAI,CAAC,IAAIpB,uBAAuB,CAAC,CAAC,CAAC;IACrD;;IAEA;IACA,MAAMqB,SAAS,GAAG,MAAM,IAAI,CAACZ,eAAe,CAACK,OAAO,CAACC,OAAO,CAAC;IAC7D,IAAIM,SAAS,CAACC,MAAM,CAAC,CAAC,EAAE;MACpB,OAAOD,SAAS;IACpB;IAEA,MAAME,QAAQ,GAAGC,eAAe,CAACH,SAAS,CAACI,KAAK,CAAC;;IAEjD;IACA,MAAMC,gBAAgB,GAAG,MAAMtB,2BAA2B,CAAC,CAAC,CAACuB,cAAc,CAACX,KAAK,CAAC;IAClF,IAAI,CAACU,gBAAgB,CAACE,OAAO,EAAE;MAC3B,MAAMC,QAAQ,GAAG3B,cAAc,CAACwB,gBAAgB,CAACI,KAAK,CAAC;MACvD,OAAOxC,MAAM,CAAC8B,IAAI,CAAC,IAAInB,oBAAoB,CAAC4B,QAAQ,CAACE,OAAO,CAAC,CAAC;IAClE;IAEA,MAAMC,IAAI,GAAG7B,qBAAqB,CAACuB,gBAAgB,CAACM,IAAI,CAAC;;IAEzD;IACA,IAAIC,MAAM,CAACC,IAAI,CAACF,IAAI,CAAC,CAACG,MAAM,KAAK,CAAC,EAAE;MAChC,OAAO7C,MAAM,CAAC8C,EAAE,CAACb,QAAQ,CAAC;IAC9B;;IAEA;IACA,MAAMc,MAAM,GAAG,IAAI,CAACxB,aAAa,CAACyB,SAAS,CAAC,CAAC;IAE7C,MAAMC,KAAe,GAAG;MACpB,GAAGhB,QAAQ;MACX,GAAGS,IAAI;MACPQ,IAAI,EAAER,IAAI,CAACQ,IAAI,IAAIjB,QAAQ,CAACiB,IAAI;MAChC;MACAC,YAAY,EACRT,IAAI,CAACS,YAAY,KAAKC,SAAS,GACzBnB,QAAQ,CAACkB,YAAY,GACpBT,IAAI,CAACS,YAAuB;MACvCE,kBAAkB,EACdX,IAAI,CAACW,kBAAkB,KAAKD,SAAS,GAC/BnB,QAAQ,CAACoB,kBAAkB,GAC3BX,IAAI,CAACW,kBAAkB;MACjCC,YAAY,EACRZ,IAAI,CAACY,YAAY,KAAKF,SAAS,GAAGnB,QAAQ,CAACqB,YAAY,GAAGZ,IAAI,CAACY,YAAY;MAC/EC,WAAW,EAAEb,IAAI,CAACa,WAAW,IAAItB,QAAQ,CAACsB,WAAW;MACrDR,MAAM,EAAEd,QAAQ,CAACc,MAAM,IAAIA,MAAM,CAACS,EAAE;MACpCC,OAAO,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;IACpC,CAAC;;IAED;IACA,MAAM/B,cAAc,GAAG,MAAM,IAAI,CAACN,aAAa,CAACM,cAAc,CAAC;MAAEqB,KAAK;MAAEpB,GAAG,EAAE;IAAI,CAAC,CAAC;IACnF,IAAI,CAACD,cAAc,EAAE;MACjB,OAAO5B,MAAM,CAAC8B,IAAI,CAACpB,uBAAuB,CAACkD,SAAS,CAACX,KAAK,CAAC,CAAC;IAChE;;IAEA;IACAA,KAAK,CAACY,IAAI,GAAG9C,aAAa,CAACkC,KAAK,CAAC;;IAEjC;IACA,MAAM,IAAI,CAAC7B,cAAc,CAAC0C,OAAO,CAC7B,IAAIzD,sBAAsB,CAAC;MAAE4C,KAAK;MAAEhB,QAAQ;MAAEP,KAAK,EAAEgB;IAAK,CAAC,CAC/D,CAAC;;IAED;IACA,MAAMqB,MAAM,GAAG,MAAM,IAAI,CAAC1C,UAAU,CAACG,OAAO,CAACyB,KAAK,EAAEhB,QAAQ,CAAC;IAC7D,IAAI8B,MAAM,CAAC/B,MAAM,CAAC,CAAC,EAAE;MACjB;MACA,MAAM,IAAI,CAACZ,cAAc,CAAC0C,OAAO,CAC7B,IAAIvD,qBAAqB,CAAC;QACtBmB,KAAK,EAAEgB,IAAI;QACXO,KAAK;QACLhB,QAAQ;QACRO,KAAK,EAAEuB,MAAM,CAACvB;MAClB,CAAC,CACL,CAAC;MACD,OAAOxC,MAAM,CAAC8B,IAAI,CAACiC,MAAM,CAACvB,KAAK,CAAC;IACpC;;IAEA;IACA,MAAM,IAAI,CAACpB,cAAc,CAAC0C,OAAO,CAAC,IAAIxD,qBAAqB,CAAC;MAAE2C,KAAK;MAAEhB;IAAS,CAAC,CAAC,CAAC;IAEjF,OAAOjC,MAAM,CAAC8C,EAAE,CAACG,KAAK,CAAC;EAC3B;AACJ;AAEA,OAAO,MAAMhD,kBAAkB,GAAGC,kBAAkB,CAAC8D,oBAAoB,CAAC;EACtEC,cAAc,EAAEhD,sBAAsB;EACtCiD,YAAY,EAAE,CACVlD,eAAe,EACfZ,cAAc,EACdD,qBAAqB,EACrBK,aAAa,EACbC,aAAa;AAErB,CAAC,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["Result","UpdateModelUseCase","UseCaseAbstraction","UpdateModelRepository","EventPublisher","ModelBeforeUpdateEvent","ModelAfterUpdateEvent","ModelUpdateErrorEvent","AccessControl","TenantContext","ModelNotAuthorizedError","ModelValidationError","createZodError","removeUndefinedValues","createModelUpdateValidation","ensureTypeTag","GetModelUseCase","UpdateModelUseCaseImpl","constructor","getModelUseCase","eventPublisher","repository","accessControl","tenantContext","execute","modelId","input","canAccess","canAccessModel","rwd","fail","getResult","isFail","original","structuredClone","value","validationResult","safeParseAsync","success","zodError","error","message","data","Object","keys","length","ok","tenant","getTenant","model","icon","titleFieldId","undefined","descriptionFieldId","imageFieldId","description","id","savedOn","Date","toISOString","fromModel","tags","publish","result","createImplementation","implementation","dependencies"],"sources":["UpdateModelUseCase.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { UpdateModelUseCase as UseCaseAbstraction } from \"./abstractions.js\";\nimport { UpdateModelRepository } from \"./abstractions.js\";\nimport { EventPublisher } from \"@webiny/api-core/features/EventPublisher\";\nimport { ModelBeforeUpdateEvent } from \"./events.js\";\nimport { ModelAfterUpdateEvent } from \"./events.js\";\nimport { ModelUpdateErrorEvent } from \"./events.js\";\nimport { AccessControl } from \"~/features/shared/abstractions.js\";\nimport { TenantContext } from \"@webiny/api-core/features/TenantContext\";\nimport { ModelNotAuthorizedError, ModelValidationError } from \"~/domain/contentModel/errors.js\";\nimport { createZodError } from \"@webiny/utils\";\nimport { removeUndefinedValues } from \"@webiny/utils\";\nimport { createModelUpdateValidation } from \"~/domain/contentModel/schemas.js\";\nimport { ensureTypeTag } from \"~/domain/contentModel/ensureTypeTag.js\";\nimport type { CmsModel } from \"~/types/index.js\";\nimport type { CmsModelUpdateInput } from \"~/types/index.js\";\nimport { GetModelUseCase } from \"~/features/contentModel/GetModel/index.js\";\n\n/**\n * UpdateModelUseCase - Core model update orchestration.\n *\n * Responsibilities:\n * - Validate input (Zod)\n * - Fetch original model\n * - Create updated domain model object\n * - Handle group changes\n * - Handle field ID changes (title, description, image)\n * - Access control checks\n * - Publish before event\n * - Delegate to repository for validation and persistence\n * - Publish after event or error event\n *\n * Note: Repository handles domain validations (API name uniqueness, field validation, etc.)\n */\nclass UpdateModelUseCaseImpl implements UseCaseAbstraction.Interface {\n public constructor(\n private getModelUseCase: GetModelUseCase.Interface,\n private eventPublisher: EventPublisher.Interface,\n private repository: UpdateModelRepository.Interface,\n private accessControl: AccessControl.Interface,\n private tenantContext: TenantContext.Interface\n ) {}\n\n async execute(\n modelId: string,\n input: CmsModelUpdateInput\n ): Promise<Result<CmsModel, UseCaseAbstraction.Error>> {\n // Initial access control check\n const canAccess = await this.accessControl.canAccessModel({ rwd: \"w\" });\n if (!canAccess) {\n return Result.fail(new ModelNotAuthorizedError());\n }\n\n // Get the original model (with access control check)\n const getResult = await this.getModelUseCase.execute(modelId);\n if (getResult.isFail()) {\n return getResult;\n }\n\n const original = structuredClone(getResult.value);\n\n // Validate input\n const validationResult = await createModelUpdateValidation().safeParseAsync(input);\n if (!validationResult.success) {\n const zodError = createZodError(validationResult.error);\n return Result.fail(\n new ModelValidationError({\n message: zodError.message,\n data: zodError.data\n })\n );\n }\n\n const data = removeUndefinedValues(validationResult.data);\n\n // If no changes, return original\n if (Object.keys(data).length === 0) {\n return Result.ok(original);\n }\n\n // Create updated model\n const tenant = this.tenantContext.getTenant();\n\n const model: CmsModel = {\n ...original,\n ...data,\n icon: data.icon ?? original.icon,\n // Handle optional field IDs explicitly\n titleFieldId:\n data.titleFieldId === undefined\n ? original.titleFieldId\n : (data.titleFieldId as string),\n descriptionFieldId:\n data.descriptionFieldId === undefined\n ? original.descriptionFieldId\n : data.descriptionFieldId,\n imageFieldId:\n data.imageFieldId === undefined ? original.imageFieldId : data.imageFieldId,\n description: data.description || original.description,\n tenant: original.tenant || tenant.id,\n savedOn: new Date().toISOString()\n };\n\n // Access control check on the updated model\n const canAccessModel = await this.accessControl.canAccessModel({ model, rwd: \"w\" });\n if (!canAccessModel) {\n return Result.fail(ModelNotAuthorizedError.fromModel(model));\n }\n\n // Ensure type tags\n model.tags = ensureTypeTag(model);\n\n // Publish before event\n await this.eventPublisher.publish(\n new ModelBeforeUpdateEvent({ model, original, input: data })\n );\n\n // Persist via repository (repository will validate)\n const result = await this.repository.execute(model, original);\n if (result.isFail()) {\n // Publish error event\n await this.eventPublisher.publish(\n new ModelUpdateErrorEvent({\n input: data,\n model,\n original,\n error: result.error\n })\n );\n return Result.fail(result.error);\n }\n\n // Publish after event\n await this.eventPublisher.publish(new ModelAfterUpdateEvent({ model, original }));\n\n return Result.ok(model);\n }\n}\n\nexport const UpdateModelUseCase = UseCaseAbstraction.createImplementation({\n implementation: UpdateModelUseCaseImpl,\n dependencies: [\n GetModelUseCase,\n EventPublisher,\n UpdateModelRepository,\n AccessControl,\n TenantContext\n ]\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -17,9 +17,9 @@ import { FieldBuilderRegistry as FieldsRegistryAbstraction, ModelFactory } from
|
|
|
17
17
|
import { AccessControl } from "../shared/abstractions.js";
|
|
18
18
|
import { ModelsProvider as ModelsProviderAbstraction } from "./models/abstractions.js";
|
|
19
19
|
import { ModelsProvider } from "./models/ModelsProvider.js";
|
|
20
|
-
import { UiFieldType } from "./fields/UiFieldType.js";
|
|
21
20
|
import { UiSeparatorFieldType } from "./fields/UiSeparatorFieldType.js";
|
|
22
21
|
import { UiAlertFieldType } from "./fields/UiAlertFieldType.js";
|
|
22
|
+
import { UiTabsFieldType } from "./fields/UiTabsFieldType.js";
|
|
23
23
|
export const ModelBuilderFeature = createFeature({
|
|
24
24
|
name: "ModelBuilder",
|
|
25
25
|
register(container) {
|
|
@@ -36,9 +36,9 @@ export const ModelBuilderFeature = createFeature({
|
|
|
36
36
|
container.register(DateTimeFieldType);
|
|
37
37
|
container.register(JsonFieldType);
|
|
38
38
|
container.register(SearchableJsonFieldType);
|
|
39
|
-
container.register(UiFieldType);
|
|
40
39
|
container.register(UiSeparatorFieldType);
|
|
41
40
|
container.register(UiAlertFieldType);
|
|
41
|
+
container.register(UiTabsFieldType);
|
|
42
42
|
// container.register(LocationFieldType);
|
|
43
43
|
|
|
44
44
|
// Register field builder registry (will automatically get all FieldType implementations)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["createFeature","FieldBuilderRegistry","TextFieldType","LongTextFieldType","RichTextFieldType","ObjectFieldType","RefFieldType","DynamicZoneFieldType","NumberFieldType","BooleanFieldType","FileFieldType","DateTimeFieldType","JsonFieldType","SearchableJsonFieldType","FieldsRegistryAbstraction","ModelFactory","AccessControl","ModelsProvider","ModelsProviderAbstraction","
|
|
1
|
+
{"version":3,"names":["createFeature","FieldBuilderRegistry","TextFieldType","LongTextFieldType","RichTextFieldType","ObjectFieldType","RefFieldType","DynamicZoneFieldType","NumberFieldType","BooleanFieldType","FileFieldType","DateTimeFieldType","JsonFieldType","SearchableJsonFieldType","FieldsRegistryAbstraction","ModelFactory","AccessControl","ModelsProvider","ModelsProviderAbstraction","UiSeparatorFieldType","UiAlertFieldType","UiTabsFieldType","ModelBuilderFeature","name","register","container","inSingletonScope","registerFactory","accessControl","undefined","resolve","resolveAll"],"sources":["feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { FieldBuilderRegistry } from \"./fields/FieldBuilderRegistry.js\";\nimport { TextFieldType } from \"./fields/TextFieldType.js\";\nimport { LongTextFieldType } from \"./fields/LongTextFieldType.js\";\nimport { RichTextFieldType } from \"./fields/RichTextFieldType.js\";\nimport { ObjectFieldType } from \"./fields/ObjectFieldType.js\";\nimport { RefFieldType } from \"./fields/RefFieldType.js\";\nimport { DynamicZoneFieldType } from \"./fields/DynamicZoneFieldType.js\";\nimport { NumberFieldType } from \"./fields/NumberFieldType.js\";\nimport { BooleanFieldType } from \"./fields/BooleanFieldType.js\";\nimport { FileFieldType } from \"./fields/FileFieldType.js\";\nimport { DateTimeFieldType } from \"./fields/DateTimeFieldType.js\";\nimport { JsonFieldType } from \"./fields/JsonFieldType.js\";\nimport { SearchableJsonFieldType } from \"./fields/SearchableJsonFieldType.js\";\n// import { LocationFieldType } from \"./fields/LocationFieldType.js\";\nimport { FieldBuilderRegistry as FieldsRegistryAbstraction, ModelFactory } from \"./abstractions.js\";\nimport { AccessControl } from \"~/features/shared/abstractions.js\";\nimport { ModelsProvider as ModelsProviderAbstraction } from \"./models/abstractions.js\";\nimport { ModelsProvider } from \"./models/ModelsProvider.js\";\nimport { UiSeparatorFieldType } from \"./fields/UiSeparatorFieldType.js\";\nimport { UiAlertFieldType } from \"./fields/UiAlertFieldType.js\";\nimport { UiTabsFieldType } from \"./fields/UiTabsFieldType.js\";\n\nexport const ModelBuilderFeature = createFeature({\n name: \"ModelBuilder\",\n register(container) {\n // Register core field types\n container.register(TextFieldType);\n container.register(LongTextFieldType);\n container.register(RichTextFieldType);\n container.register(ObjectFieldType);\n container.register(RefFieldType);\n container.register(DynamicZoneFieldType);\n container.register(NumberFieldType);\n container.register(BooleanFieldType);\n container.register(FileFieldType);\n container.register(DateTimeFieldType);\n container.register(JsonFieldType);\n container.register(SearchableJsonFieldType);\n container.register(UiSeparatorFieldType);\n container.register(UiAlertFieldType);\n container.register(UiTabsFieldType);\n // container.register(LocationFieldType);\n\n // Register field builder registry (will automatically get all FieldType implementations)\n container.register(FieldBuilderRegistry).inSingletonScope();\n\n // Register unified models provider\n container.registerFactory(ModelsProviderAbstraction, () => {\n let accessControl: AccessControl.Interface | undefined = undefined;\n try {\n // TODO: add `container.resolveOptional`\n accessControl = container.resolve(AccessControl);\n } catch {\n // It's an optional dependency!\n }\n\n return new ModelsProvider(\n // TODO: introduce a `lazy: true` dependency modifier, which will inject a getter.\n () => container.resolveAll(ModelFactory),\n container.resolve(FieldsRegistryAbstraction),\n accessControl\n );\n });\n }\n});\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,qBAAqB;AACnD,SAASC,oBAAoB;AAC7B,SAASC,aAAa;AACtB,SAASC,iBAAiB;AAC1B,SAASC,iBAAiB;AAC1B,SAASC,eAAe;AACxB,SAASC,YAAY;AACrB,SAASC,oBAAoB;AAC7B,SAASC,eAAe;AACxB,SAASC,gBAAgB;AACzB,SAASC,aAAa;AACtB,SAASC,iBAAiB;AAC1B,SAASC,aAAa;AACtB,SAASC,uBAAuB;AAChC;AACA,SAASZ,oBAAoB,IAAIa,yBAAyB,EAAEC,YAAY;AACxE,SAASC,aAAa;AACtB,SAASC,cAAc,IAAIC,yBAAyB;AACpD,SAASD,cAAc;AACvB,SAASE,oBAAoB;AAC7B,SAASC,gBAAgB;AACzB,SAASC,eAAe;AAExB,OAAO,MAAMC,mBAAmB,GAAGtB,aAAa,CAAC;EAC7CuB,IAAI,EAAE,cAAc;EACpBC,QAAQA,CAACC,SAAS,EAAE;IAChB;IACAA,SAAS,CAACD,QAAQ,CAACtB,aAAa,CAAC;IACjCuB,SAAS,CAACD,QAAQ,CAACrB,iBAAiB,CAAC;IACrCsB,SAAS,CAACD,QAAQ,CAACpB,iBAAiB,CAAC;IACrCqB,SAAS,CAACD,QAAQ,CAACnB,eAAe,CAAC;IACnCoB,SAAS,CAACD,QAAQ,CAAClB,YAAY,CAAC;IAChCmB,SAAS,CAACD,QAAQ,CAACjB,oBAAoB,CAAC;IACxCkB,SAAS,CAACD,QAAQ,CAAChB,eAAe,CAAC;IACnCiB,SAAS,CAACD,QAAQ,CAACf,gBAAgB,CAAC;IACpCgB,SAAS,CAACD,QAAQ,CAACd,aAAa,CAAC;IACjCe,SAAS,CAACD,QAAQ,CAACb,iBAAiB,CAAC;IACrCc,SAAS,CAACD,QAAQ,CAACZ,aAAa,CAAC;IACjCa,SAAS,CAACD,QAAQ,CAACX,uBAAuB,CAAC;IAC3CY,SAAS,CAACD,QAAQ,CAACL,oBAAoB,CAAC;IACxCM,SAAS,CAACD,QAAQ,CAACJ,gBAAgB,CAAC;IACpCK,SAAS,CAACD,QAAQ,CAACH,eAAe,CAAC;IACnC;;IAEA;IACAI,SAAS,CAACD,QAAQ,CAACvB,oBAAoB,CAAC,CAACyB,gBAAgB,CAAC,CAAC;;IAE3D;IACAD,SAAS,CAACE,eAAe,CAACT,yBAAyB,EAAE,MAAM;MACvD,IAAIU,aAAkD,GAAGC,SAAS;MAClE,IAAI;QACA;QACAD,aAAa,GAAGH,SAAS,CAACK,OAAO,CAACd,aAAa,CAAC;MACpD,CAAC,CAAC,MAAM;QACJ;MAAA;MAGJ,OAAO,IAAIC,cAAc;MACrB;MACA,MAAMQ,SAAS,CAACM,UAAU,CAAChB,YAAY,CAAC,EACxCU,SAAS,CAACK,OAAO,CAAChB,yBAAyB,CAAC,EAC5Cc,aACJ,CAAC;IACL,CAAC,CAAC;EACN;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CmsModelField, CmsModelLayoutCell } from "../../../types/index.js";
|
|
2
|
+
export interface DataFieldBuildResult {
|
|
3
|
+
type: "data";
|
|
4
|
+
field: CmsModelField;
|
|
5
|
+
}
|
|
6
|
+
export interface LayoutFieldBuildResult {
|
|
7
|
+
type: "layout";
|
|
8
|
+
layoutCell: CmsModelLayoutCell;
|
|
9
|
+
fields?: CmsModelField[];
|
|
10
|
+
}
|
|
11
|
+
export type FieldBuildResult = DataFieldBuildResult | LayoutFieldBuildResult;
|
|
12
|
+
export interface BaseFieldBuilderConfig {
|
|
13
|
+
label: string;
|
|
14
|
+
help?: string | null;
|
|
15
|
+
description?: string | null;
|
|
16
|
+
note?: string | null;
|
|
17
|
+
_fieldId?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Minimal shared base class for all field builders (data and layout).
|
|
21
|
+
*/
|
|
22
|
+
export declare abstract class BaseFieldBuilder<TType extends string = string> {
|
|
23
|
+
readonly type: TType;
|
|
24
|
+
protected config: BaseFieldBuilderConfig;
|
|
25
|
+
constructor(type: TType, label?: string);
|
|
26
|
+
label(text: string): this;
|
|
27
|
+
help(text: string): this;
|
|
28
|
+
description(text: string): this;
|
|
29
|
+
note(text: string): this;
|
|
30
|
+
fieldId(id: string): this;
|
|
31
|
+
/**
|
|
32
|
+
* Build the final field result.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
abstract build(): FieldBuildResult;
|
|
36
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal shared base class for all field builders (data and layout).
|
|
3
|
+
*/
|
|
4
|
+
export class BaseFieldBuilder {
|
|
5
|
+
constructor(type, label) {
|
|
6
|
+
this.type = type;
|
|
7
|
+
this.config = {
|
|
8
|
+
label: label || "",
|
|
9
|
+
help: null,
|
|
10
|
+
description: null,
|
|
11
|
+
note: null
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
label(text) {
|
|
15
|
+
this.config.label = text;
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
help(text) {
|
|
19
|
+
this.config.help = text;
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
description(text) {
|
|
23
|
+
this.config.description = text;
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
note(text) {
|
|
27
|
+
this.config.note = text;
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
fieldId(id) {
|
|
31
|
+
this.config._fieldId = id;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Build the final field result.
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=BaseFieldBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["BaseFieldBuilder","constructor","type","label","config","help","description","note","text","fieldId","id","_fieldId"],"sources":["BaseFieldBuilder.ts"],"sourcesContent":["import type { CmsModelField, CmsModelLayoutCell } from \"~/types/index.js\";\n\nexport interface DataFieldBuildResult {\n type: \"data\";\n field: CmsModelField;\n}\n\nexport interface LayoutFieldBuildResult {\n type: \"layout\";\n layoutCell: CmsModelLayoutCell;\n fields?: CmsModelField[];\n}\n\nexport type FieldBuildResult = DataFieldBuildResult | LayoutFieldBuildResult;\n\nexport interface BaseFieldBuilderConfig {\n label: string;\n help?: string | null;\n description?: string | null;\n note?: string | null;\n _fieldId?: string;\n}\n\n/**\n * Minimal shared base class for all field builders (data and layout).\n */\nexport abstract class BaseFieldBuilder<TType extends string = string> {\n public readonly type: TType;\n protected config: BaseFieldBuilderConfig;\n\n public constructor(type: TType, label?: string) {\n this.type = type;\n this.config = {\n label: label || \"\",\n help: null,\n description: null,\n note: null\n };\n }\n\n label(text: string): this {\n this.config.label = text;\n return this;\n }\n\n help(text: string): this {\n this.config.help = text;\n return this;\n }\n\n description(text: string): this {\n this.config.description = text;\n return this;\n }\n\n note(text: string): this {\n this.config.note = text;\n return this;\n }\n\n fieldId(id: string): this {\n this.config._fieldId = id;\n return this;\n }\n\n /**\n * Build the final field result.\n * @internal\n */\n abstract build(): FieldBuildResult;\n}\n"],"mappings":"AAuBA;AACA;AACA;AACA,OAAO,MAAeA,gBAAgB,CAAgC;EAI3DC,WAAWA,CAACC,IAAW,EAAEC,KAAc,EAAE;IAC5C,IAAI,CAACD,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACE,MAAM,GAAG;MACVD,KAAK,EAAEA,KAAK,IAAI,EAAE;MAClBE,IAAI,EAAE,IAAI;MACVC,WAAW,EAAE,IAAI;MACjBC,IAAI,EAAE;IACV,CAAC;EACL;EAEAJ,KAAKA,CAACK,IAAY,EAAQ;IACtB,IAAI,CAACJ,MAAM,CAACD,KAAK,GAAGK,IAAI;IACxB,OAAO,IAAI;EACf;EAEAH,IAAIA,CAACG,IAAY,EAAQ;IACrB,IAAI,CAACJ,MAAM,CAACC,IAAI,GAAGG,IAAI;IACvB,OAAO,IAAI;EACf;EAEAF,WAAWA,CAACE,IAAY,EAAQ;IAC5B,IAAI,CAACJ,MAAM,CAACE,WAAW,GAAGE,IAAI;IAC9B,OAAO,IAAI;EACf;EAEAD,IAAIA,CAACC,IAAY,EAAQ;IACrB,IAAI,CAACJ,MAAM,CAACG,IAAI,GAAGC,IAAI;IACvB,OAAO,IAAI;EACf;EAEAC,OAAOA,CAACC,EAAU,EAAQ;IACtB,IAAI,CAACN,MAAM,CAACO,QAAQ,GAAGD,EAAE;IACzB,OAAO,IAAI;EACf;;EAEA;AACJ;AACA;AACA;AAEA","ignoreList":[]}
|