diff --git a/src/commands/app/create.ts b/src/commands/app/create.ts index f824efd..974b94d 100644 --- a/src/commands/app/create.ts +++ b/src/commands/app/create.ts @@ -1,5 +1,6 @@ import * as tmp from "tmp"; import AdmZip from "adm-zip"; +import omit from "lodash/omit"; import pick from "lodash/pick"; import * as shell from "shelljs"; import merge from "lodash/merge"; @@ -14,7 +15,13 @@ import { writeFileSync, createWriteStream, } from "fs"; -import { ux, cliux, flags, HttpClient, configHandler } from "@contentstack/cli-utilities"; +import { + ux, + cliux, + flags, + HttpClient, + configHandler, +} from "@contentstack/cli-utilities"; import { BaseCommand } from "../../base-command"; import { AppManifest, AppType } from "../../types"; @@ -28,6 +35,11 @@ import { export default class Create extends BaseCommand { private appData!: AppManifest; + private tempAppData = { + name: "", + target_type: "", + ui_location: { locations: undefined }, + } as any; static description = "Create a new app in Developer Hub and optionally clone a boilerplate locally."; @@ -62,15 +74,14 @@ export default class Create extends BaseCommand { async run(): Promise { this.sharedConfig.org = this.flags.org; this.sharedConfig.appName = this.flags.name; - this.appData = require(this.sharedConfig.manifestPath); await this.flagsPromptQueue(); - this.appData.name = this.sharedConfig.appName; - this.appData.target_type = this.flags["app-type"] as AppType; + this.tempAppData.name = this.sharedConfig.appName; + this.tempAppData.target_type = this.flags["app-type"] as AppType; if (this.flags["app-type"] === AppType.ORGANIZATION) { - this.appData.ui_location.locations = getOrgAppUiLocation(); + this.tempAppData.ui_location.locations = getOrgAppUiLocation(); } try { @@ -84,6 +95,7 @@ export default class Create extends BaseCommand { ) { await this.boilerplateFlow(); } else { + this.manageManifestToggeling(); await this.registerTheAppOnDeveloperHub(false); } } catch (error: Error | any) { @@ -105,6 +117,8 @@ export default class Create extends BaseCommand { await this.unZipBoilerplate(await this.cloneBoilerplate()); tmp.setGracefulCleanup(); // NOTE If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit + this.manageManifestToggeling(); + // NOTE Step 2: Registering the app await this.registerTheAppOnDeveloperHub(); @@ -114,7 +128,7 @@ export default class Create extends BaseCommand { ux.action.stop(); this.log( this.$t(this.messages.START_APP_COMMAND, { - command: `cd ${this.sharedConfig.folderPath} && npm run start`, + command: `cd "${this.sharedConfig.folderPath}" && npm run start`, }), "info" ); @@ -133,10 +147,12 @@ export default class Create extends BaseCommand { } //Auto select org in case of oauth - this.sharedConfig.org = configHandler.get('oauthOrgUid') ?? (await getOrg(this.flags, { - log: this.log, - managementSdk: this.managementSdk, - })); + this.sharedConfig.org = + configHandler.get("oauthOrgUid") ?? + (await getOrg(this.flags, { + log: this.log, + managementSdk: this.managementSdk, + })); } /** @@ -208,6 +224,34 @@ export default class Create extends BaseCommand { }); } + /** + * @method manageManifestToggeling + * + * The function manages toggling of the manifest file based on the app type, removing the + * "ui_location" property if the app type is an organization. + */ + manageManifestToggeling() { + // NOTE Use boilerplate manifest if exist + const manifestPath = resolve( + this.sharedConfig.folderPath || "", + "manifest.json" + ); + + if (existsSync(manifestPath)) { + this.sharedConfig.manifestPath = manifestPath; + } + + let manifest = require(this.sharedConfig.manifestPath); + + if (this.flags["app-type"] === AppType.ORGANIZATION) { + manifest = omit(manifest, ["ui_location"]); + } else { + this.tempAppData = omit(this.tempAppData, ["ui_location"]); + } + + this.appData = merge(manifest, this.tempAppData); + } + /** * @method registerTheAppOnDeveloperHub * diff --git a/src/commands/app/update.ts b/src/commands/app/update.ts index 05d3a25..c4a8ef2 100644 --- a/src/commands/app/update.ts +++ b/src/commands/app/update.ts @@ -7,7 +7,7 @@ import { existsSync, readFileSync, writeFileSync } from "fs"; import { $t, appUpdate } from "../../messages"; import { fetchApp, getApp, getOrg } from "../../util"; -import {AppCLIBaseCommand} from "../../app-cli-base-coomand"; +import { AppCLIBaseCommand } from "../../app-cli-base-coomand"; export default class Update extends AppCLIBaseCommand { private orgUid!: string; @@ -28,12 +28,14 @@ export default class Update extends AppCLIBaseCommand { async run(): Promise { try { - //if working directory isn't app directory - if(!this.manifestData){ + // if working directory isn't app directory + if (!this.manifestData) { await this.validateManifest(); } - this.flags["app-manifest"] = this.manifestPath ?? this.flags["app-manifest"]; - this.orgUid = this.flags.org ?? this.manifestData?.organization_uid; + + this.flags["app-manifest"] = + this.manifestPath ?? this.flags["app-manifest"]; + this.orgUid = this.flags.org ?? this.manifestData?.organization_uid; this.sharedConfig.org = await getOrg( { org: this.orgUid as any }, { diff --git a/src/config/manifest.json b/src/config/manifest.json index 2b501d9..30f03ec 100644 --- a/src/config/manifest.json +++ b/src/config/manifest.json @@ -1,10 +1,11 @@ { - "icon": "", "description": "", - "target_type": "stack", + "icon": "", "name": "", - "visibility": "private", "organization_uid": "", + "target_type": "stack", + "visibility": "private", + "uid": "", "ui_location": { "signed": false, "base_url": "http://localhost:3000", @@ -13,20 +14,22 @@ "type": "cs.cm.stack.custom_field", "meta": [ { - "path": "/custom-field", - "signed": true, + "multiple": false, + "path": "/#/custom-field", + "signed": false, "enabled": true, - "data_type": "number" + "data_type": "json" } ] }, { - "type": "cs.cm.stack.config", + "type": "cs.cm.stack.dashboard", "meta": [ { - "path": "/app-configuration", - "signed": true, - "enabled": true + "path": "/#/stack-dashboard", + "signed": false, + "enabled": true, + "default_width": "half" } ] }, @@ -35,35 +38,68 @@ "meta": [ { "blur": false, - "path": "/asset-sidebar", - "signed": true, + "path": "/#/asset-sidebar", + "signed": false, "enabled": true, "width": 500 } ] }, { - "type": "cs.cm.stack.dashboard", + "type": "cs.cm.stack.sidebar", "meta": [ { - "path": "/stack-dashboard", - "signed": true, + "path": "/#/entry-sidebar", + "signed": false, + "enabled": true + } + ] + }, + { + "type": "cs.cm.stack.full_page", + "meta": [ + { + "path": "/#/full-page", + "signed": false, + "enabled": true + } + ] + }, + { + "type": "cs.cm.stack.field_modifier", + "meta": [ + { + "path": "/#/field-modifier", + "signed": false, "enabled": true, - "default_width": "half" + "allowed_types": ["$all"] } ] }, { - "type": "cs.cm.stack.sidebar", + "type": "cs.cm.stack.config", + "meta": [ + { + "path": "/#/app-configuration", + "signed": false, + "enabled": true + } + ] + }, + { + "type": "cs.cm.stack.rte", "meta": [ { - "path": "/entry-sidebar", - "signed": true, + "path": "/json-rte.js", + "signed": false, "enabled": true } ] } ] }, - "uid": "" + "hosting": { + "provider": "external", + "deployment_url": "http://localhost:3000" + } } diff --git a/test/unit/commands/app/create.test.ts b/test/unit/commands/app/create.test.ts index a6d0ff3..587a6f5 100644 --- a/test/unit/commands/app/create.test.ts +++ b/test/unit/commands/app/create.test.ts @@ -13,7 +13,7 @@ import messages from "../../../../src/messages"; import * as mock from "../../mock/common.mock.json"; import manifestData from "../../../../src/config/manifest.json"; -const gitHubHost = "https://github.com"; +const { origin, pathname } = new URL(config.appBoilerplateGithubUrl); const zipPath = join(process.cwd(), "test", "unit", "mock", "boilerplate.zip"); const region: { cma: string; name: string; cda: string } = configHandler.get("region"); @@ -50,10 +50,8 @@ describe("app:create", () => { return (cases as Record)[prompt.name]; }) - .nock(gitHubHost, (api) => - api - .get(config.appBoilerplateGithubUrl.replace(gitHubHost, "")) - .reply(200, { data: "test-data" }) + .nock(origin, (api) => + api.get(pathname).reply(200, { data: "test-data" }) ) .nock(region.cma, (api) => api @@ -98,10 +96,8 @@ describe("app:create", () => { return (cases as Record)[prompt.name]; }) - .nock(gitHubHost, (api) => - api - .get(config.appBoilerplateGithubUrl.replace(gitHubHost, "")) - .reply(200, { data: "test-data" }) + .nock(origin, (api) => + api.get(pathname).reply(200, { data: "test-data" }) ) .nock(region.cma, (api) => api @@ -195,11 +191,7 @@ describe("app:create", () => { return (cases as Record)[prompt.name]; }) - .nock(gitHubHost, (api) => - api - .get(config.appBoilerplateGithubUrl.replace(gitHubHost, "")) - .reply(200) - ) + .nock(origin, (api) => api.get(pathname).reply(200)) .nock(region.cma, (api) => api .get("/v3/organizations?limit=100&asc=name&include_count=true&skip=0") @@ -305,10 +297,8 @@ describe("app:create", () => { return (cases as Record)[prompt.name]; }) - .nock(gitHubHost, (api) => - api - .get(config.appBoilerplateGithubUrl.replace(gitHubHost, "")) - .reply(200, { data: "test-data" }) + .nock(origin, (api) => + api.get(pathname).reply(200, { data: "test-data" }) ) .nock(region.cma, (api) => api