antelope-cli 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/ansible/onboarding-ca/README.md +105 -105
  2. package/ansible/onboarding-ca/onboard-ca.yml +43 -51
  3. package/ansible/onboarding-ca/requirements.yml +8 -8
  4. package/ansible/onboarding-ca/roles/onboard_ca/defaults/main.yml +77 -49
  5. package/ansible/onboarding-ca/roles/onboard_ca/meta/main.yml +10 -10
  6. package/ansible/onboarding-ca/roles/onboard_ca/tasks/main.yml +311 -193
  7. package/ansible/onboarding-ca/roles/onboard_ca/tasks/per_branch.yml +114 -107
  8. package/ansible/onboarding-ca/roles/onboard_ca/vars/main.yml +9 -9
  9. package/ansible/onboarding-crm/README.md +107 -0
  10. package/ansible/onboarding-crm/onboard-crm.yml +60 -0
  11. package/ansible/onboarding-crm/requirements.yml +8 -0
  12. package/ansible/onboarding-crm/roles/onboard_crm/defaults/main.yml +99 -0
  13. package/ansible/onboarding-crm/roles/onboard_crm/meta/main.yml +10 -0
  14. package/ansible/onboarding-crm/roles/onboard_crm/tasks/main.yml +324 -0
  15. package/ansible/onboarding-crm/roles/onboard_crm/tasks/per_branch.yml +121 -0
  16. package/ansible/onboarding-crm/roles/onboard_crm/vars/main.yml +9 -0
  17. package/index.js +12 -12
  18. package/onboarding/brand.js +21 -21
  19. package/onboarding/createConfig.js +71 -71
  20. package/onboarding/favicon.js +24 -24
  21. package/onboarding/index.js +62 -62
  22. package/onboarding/logo.js +16 -16
  23. package/onboarding/themes.js +92 -92
  24. package/onboarding/translations.js +41 -41
  25. package/onboarding/variablesColors.js +58 -58
  26. package/onboarding-ca/brand.js +13 -13
  27. package/onboarding-ca/index.js +94 -94
  28. package/onboarding-ca/riskDisclaimer.js +27 -27
  29. package/onboarding-ca/scss.js +24 -24
  30. package/onboarding-ca/templates/risk-disclaimer.html +12 -12
  31. package/onboarding-crm/brand.js +22 -22
  32. package/onboarding-crm/brandLogos.js +31 -0
  33. package/onboarding-crm/createConfig.js +40 -40
  34. package/onboarding-crm/index.js +175 -171
  35. package/onboarding-crm/themes.js +92 -92
  36. package/onboarding-crm/variablesColors.js +53 -53
  37. package/package.json +30 -30
@@ -1,171 +1,175 @@
1
- const readline = require('readline');
2
- const chalk = require('chalk');
3
- const brandModule = require('./brand.js');
4
- const variablesColors = require('./variablesColors.js');
5
- const themes = require('./themes.js');
6
- const translations = require('./translations.js');
7
- const createConfig = require('./createConfig.js');
8
- const brandLocations = require('./brandLocations.js');
9
-
10
- const ALLOWED_TYPES = ['CORP_FL', 'IB_FL', 'CORP_AFF_FL', 'CORP_AFF_IB_PORTAL', 'CORP_AFF_MSQ'];
11
- const DEFAULT_BASE_URL = 'https://dev-apicrm.antelopesystem.com/SignalsCRM/';
12
-
13
- const HELP = `
14
- Usage: ant-cli onboarding-crm --brand_id <id> --brand_name <name> [options]
15
-
16
- Onboards a CRM brand in the current web-crm checkout, keyed by the brand's Antelope ID.
17
- All inputs come from flags (interactive prompts are only a fallback in a TTY):
18
- src/ng1/assets/css/sass/variables-colors.scss (+ $<id> shades and $colors entry)
19
- src/ng1/assets/css/sass/materialism/themes.scss (+ theme maps and .theme-template-<id> block)
20
- src/assets/brands/<id>/languages/<lang>.json (one empty file per language)
21
- src/configs/configs.ts (rewritten for the brand — copy into Consul)
22
- BRAND_LOCATIONS.md (+ sprint tracking row "<name> -> <id>")
23
-
24
- Options:
25
- --brand_id <id> Antelope unique ID, e.g. "xxxxx" — the code identifier used everywhere (required)
26
- --brand_name <name> Human brand name — recorded in the BRAND_LOCATIONS.md tracking row (required)
27
- --color <hex> Brand hex color, e.g. "#1a2b3c". Empty => default palette ($corp)
28
- --logo_url <url> Logo image URL (black background) (required)
29
- --languages <csv> 2-letter language codes, comma-separated, e.g. "en,ar" (required)
30
- --favicon_url <url> Favicon image URL configs.ts favicon (required)
31
- --fcm_sender_id <id> Firebase FCMSenderId configs.ts (required)
32
- --type <type> One of: ${ALLOWED_TYPES.join(', ')} → configs.ts (required)
33
- --base_url <url> configs.ts baseUrl. Default: ${DEFAULT_BASE_URL}
34
- -h, --help Show this help
35
-
36
- Run from the root of a web-crm checkout files are written relative to the current directory.
37
- `;
38
-
39
- const FLAGS = {
40
- '--brand_id': 'brandId',
41
- '--brand_name': 'brandName',
42
- '--color': 'color',
43
- '--logo_url': 'logo',
44
- '--languages': 'languages',
45
- '--favicon_url': 'favicon',
46
- '--fcm_sender_id': 'fcmSenderId',
47
- '--type': 'type',
48
- '--base_url': 'baseUrl'
49
- };
50
-
51
- function parseArgs(argv) {
52
- const opts = {};
53
- for (let i = 0; i < argv.length; i++) {
54
- const a = argv[i];
55
- if (a === '--help' || a === '-h') opts.help = true;
56
- else if (FLAGS[a]) opts[FLAGS[a]] = argv[++i];
57
- }
58
- return opts;
59
- }
60
-
61
- // Antelope IDs are lowercase alphanumeric; normalize defensively (trim, lowercase, drop spaces).
62
- const normalizeId = (value) => value.trim().toLowerCase().replace(/ /g, '');
63
-
64
- const ask = (rl, question) => new Promise((resolve) => rl.question(question, (a) => resolve(a)));
65
-
66
- // Resolve a value: prefer the flag; otherwise prompt (interactive only). Returns undefined
67
- // when absent and non-interactive, so the caller can report it as a missing required field.
68
- async function resolve(opts, key, promptText, interactive, rl) {
69
- if (opts[key] !== undefined) return opts[key];
70
- if (interactive) return ask(rl, promptText);
71
- return undefined;
72
- }
73
-
74
- async function run() {
75
- const opts = parseArgs(process.argv.slice(3));
76
- if (opts.help) {
77
- console.log(HELP);
78
- return;
79
- }
80
-
81
- console.log(chalk.underline(chalk.cyan('Antelope CRM on-boarding\n')));
82
-
83
- // Interactive only in a real terminal and when not forced non-interactive (CI / Ansible).
84
- const interactive = Boolean(process.stdin.isTTY) && !process.env.CI;
85
- const rl = interactive ? readline.createInterface({ input: process.stdin, output: process.stdout }) : null;
86
-
87
- try {
88
- const brandIdRaw = await resolve(opts, 'brandId', "Enter the brand's Antelope ID (e.g. xxxxx):\n", interactive, rl);
89
- const brandName = await resolve(opts, 'brandName', "What is the new brand's name?\n", interactive, rl);
90
- const connectedBrandName = brandIdRaw ? normalizeId(brandIdRaw) : '';
91
-
92
- // Color is optional (empty => default palette).
93
- const color = opts.color !== undefined
94
- ? opts.color
95
- : (interactive ? await ask(rl, `Please set a color for "${connectedBrandName}", use hex value, leave empty for default.\n`) : '');
96
-
97
- const logo = await resolve(opts, 'logo', 'Please enter the URL to the logo image suitable for a black background:\n', interactive, rl);
98
- const favicon = await resolve(opts, 'favicon', 'Please provide the url to your favicon image:\n', interactive, rl);
99
- const languagesInput = await resolve(opts, 'languages', 'Enter the languages (2-letter codes) separated by commas:\n', interactive, rl);
100
- const fcmSenderId = await resolve(opts, 'fcmSenderId', 'Enter the FCMSenderId value (see https://xsites.atlassian.net/wiki/spaces/IKB/pages/777650347/Onboarding+Branding+Manual+for+devs#Firebase): ', interactive, rl);
101
- const typeInput = await resolve(opts, 'type', `Enter the type value (allowed values: ${ALLOWED_TYPES.join(', ')}): `, interactive, rl);
102
-
103
- // baseUrl is optional (defaults to the dev URL).
104
- const baseUrl = opts.baseUrl !== undefined && opts.baseUrl !== ''
105
- ? opts.baseUrl
106
- : (interactive ? (await ask(rl, `Enter the configs.ts baseUrl (leave empty for ${DEFAULT_BASE_URL}):\n`)) || DEFAULT_BASE_URL : DEFAULT_BASE_URL);
107
-
108
- // Validate required fields.
109
- const missing = [];
110
- if (!connectedBrandName) missing.push('--brand_id');
111
- if (!brandName) missing.push('--brand_name');
112
- if (!logo) missing.push('--logo_url');
113
- if (!favicon) missing.push('--favicon_url');
114
- if (!languagesInput) missing.push('--languages');
115
- if (!fcmSenderId) missing.push('--fcm_sender_id');
116
- if (!typeInput) missing.push('--type');
117
- if (missing.length) {
118
- console.error(chalk.red(`Error: missing required value(s): ${missing.join(', ')}`));
119
- console.log(HELP);
120
- process.exitCode = 1;
121
- return;
122
- }
123
-
124
- const type = typeInput.toUpperCase();
125
- if (!ALLOWED_TYPES.includes(type)) {
126
- console.error(chalk.red(`Error: invalid --type "${typeInput}". Allowed: ${ALLOWED_TYPES.join(', ')}`));
127
- process.exitCode = 1;
128
- return;
129
- }
130
-
131
- const languages = languagesInput.trim().split(',').map((l) => l.trim()).filter(Boolean);
132
- if (!languages.length) {
133
- console.error(chalk.red('Error: --languages must contain at least one 2-letter code.'));
134
- process.exitCode = 1;
135
- return;
136
- }
137
-
138
- brandModule.updateBrand({
139
- brandId: connectedBrandName,
140
- brandName,
141
- connectedBrandName,
142
- color: color || '',
143
- logo,
144
- languages,
145
- favicon,
146
- FCMSenderId: fcmSenderId,
147
- type,
148
- baseUrl
149
- });
150
-
151
- console.log(chalk.bold(chalk.yellow(`\nOnboarding "${brandName}" (id: ${connectedBrandName})`)));
152
- console.log(chalk.bold(chalk.yellow('\nStep 1: Add to variables-colors.scss')));
153
- await variablesColors.start();
154
- console.log(chalk.bold(chalk.yellow('\nStep 2: Add to themes.scss')));
155
- await themes.start();
156
- console.log(chalk.bold(chalk.yellow('\nStep 3: Adding translations')));
157
- await translations.start();
158
- console.log(chalk.bold(chalk.yellow('\nStep 4: Editing the config file')));
159
- await createConfig.start();
160
- console.log(chalk.bold(chalk.yellow('\nStep 5: Recording in BRAND_LOCATIONS.md')));
161
- await brandLocations.start();
162
- console.log(chalk.green('\nCRM onboarding completed!'));
163
- } catch (err) {
164
- console.error(chalk.red(err) + '\n Please delete files and code added by this failed session.');
165
- process.exitCode = 1;
166
- } finally {
167
- if (rl) rl.close();
168
- }
169
- }
170
-
171
- run();
1
+ const readline = require('readline');
2
+ const chalk = require('chalk');
3
+ const brandModule = require('./brand.js');
4
+ const variablesColors = require('./variablesColors.js');
5
+ const themes = require('./themes.js');
6
+ const translations = require('./translations.js');
7
+ const createConfig = require('./createConfig.js');
8
+ const brandLogos = require('./brandLogos.js');
9
+ const brandLocations = require('./brandLocations.js');
10
+
11
+ const ALLOWED_TYPES = ['CORP_FL', 'IB_FL', 'CORP_AFF_FL', 'CORP_AFF_IB_PORTAL', 'CORP_AFF_MSQ'];
12
+ const DEFAULT_BASE_URL = 'https://dev-apicrm.antelopesystem.com/SignalsCRM/';
13
+
14
+ const HELP = `
15
+ Usage: ant-cli onboarding-crm --brand_id <id> --brand_name <name> [options]
16
+
17
+ Onboards a CRM brand in the current web-crm checkout, keyed by the brand's Antelope ID.
18
+ All inputs come from flags (interactive prompts are only a fallback in a TTY):
19
+ src/ng1/assets/css/sass/variables-colors.scss (+ $<id> shades and $colors entry)
20
+ src/ng1/assets/css/sass/materialism/themes.scss (+ theme maps and .theme-template-<id> block)
21
+ src/assets/brands/<id>/languages/<lang>.json (one empty file per language)
22
+ src/configs/configs.ts (rewritten for the brand copy into Consul; gitignored)
23
+ src/configs/brand-logos.json (+ "theme-template-<id>": "<logo_url>" entry)
24
+ BRAND_LOCATIONS.md (+ sprint tracking row "<name> -> <id>")
25
+
26
+ Options:
27
+ --brand_id <id> Antelope unique ID, e.g. "xxxxx" the code identifier used everywhere (required)
28
+ --brand_name <name> Human brand name recorded in the BRAND_LOCATIONS.md tracking row (required)
29
+ --color <hex> Brand hex color, e.g. "#1a2b3c". Empty => default palette ($corp)
30
+ --logo_url <url> Logo image URL (black background) (required)
31
+ --languages <csv> 2-letter language codes, comma-separated, e.g. "en,ar" (required)
32
+ --favicon_url <url> Favicon image URL → configs.ts favicon (required)
33
+ --fcm_sender_id <id> Firebase FCMSenderId → configs.ts (required)
34
+ --type <type> One of: ${ALLOWED_TYPES.join(', ')} configs.ts (required)
35
+ --base_url <url> configs.ts baseUrl. Default: ${DEFAULT_BASE_URL}
36
+ -h, --help Show this help
37
+
38
+ Run from the root of a web-crm checkout — files are written relative to the current directory.
39
+ `;
40
+
41
+ const FLAGS = {
42
+ '--brand_id': 'brandId',
43
+ '--brand_name': 'brandName',
44
+ '--color': 'color',
45
+ '--logo_url': 'logo',
46
+ '--languages': 'languages',
47
+ '--favicon_url': 'favicon',
48
+ '--fcm_sender_id': 'fcmSenderId',
49
+ '--type': 'type',
50
+ '--base_url': 'baseUrl'
51
+ };
52
+
53
+ function parseArgs(argv) {
54
+ const opts = {};
55
+ for (let i = 0; i < argv.length; i++) {
56
+ const a = argv[i];
57
+ if (a === '--help' || a === '-h') opts.help = true;
58
+ else if (FLAGS[a]) opts[FLAGS[a]] = argv[++i];
59
+ }
60
+ return opts;
61
+ }
62
+
63
+ // Antelope IDs are lowercase alphanumeric; normalize defensively (trim, lowercase, drop spaces).
64
+ const normalizeId = (value) => value.trim().toLowerCase().replace(/ /g, '');
65
+
66
+ const ask = (rl, question) => new Promise((resolve) => rl.question(question, (a) => resolve(a)));
67
+
68
+ // Resolve a value: prefer the flag; otherwise prompt (interactive only). Returns undefined
69
+ // when absent and non-interactive, so the caller can report it as a missing required field.
70
+ async function resolve(opts, key, promptText, interactive, rl) {
71
+ if (opts[key] !== undefined) return opts[key];
72
+ if (interactive) return ask(rl, promptText);
73
+ return undefined;
74
+ }
75
+
76
+ async function run() {
77
+ const opts = parseArgs(process.argv.slice(3));
78
+ if (opts.help) {
79
+ console.log(HELP);
80
+ return;
81
+ }
82
+
83
+ console.log(chalk.underline(chalk.cyan('Antelope CRM on-boarding\n')));
84
+
85
+ // Interactive only in a real terminal and when not forced non-interactive (CI / Ansible).
86
+ const interactive = Boolean(process.stdin.isTTY) && !process.env.CI;
87
+ const rl = interactive ? readline.createInterface({ input: process.stdin, output: process.stdout }) : null;
88
+
89
+ try {
90
+ const brandIdRaw = await resolve(opts, 'brandId', "Enter the brand's Antelope ID (e.g. xxxxx):\n", interactive, rl);
91
+ const brandName = await resolve(opts, 'brandName', "What is the new brand's name?\n", interactive, rl);
92
+ const connectedBrandName = brandIdRaw ? normalizeId(brandIdRaw) : '';
93
+
94
+ // Color is optional (empty => default palette).
95
+ const color = opts.color !== undefined
96
+ ? opts.color
97
+ : (interactive ? await ask(rl, `Please set a color for "${connectedBrandName}", use hex value, leave empty for default.\n`) : '');
98
+
99
+ const logo = await resolve(opts, 'logo', 'Please enter the URL to the logo image suitable for a black background:\n', interactive, rl);
100
+ const favicon = await resolve(opts, 'favicon', 'Please provide the url to your favicon image:\n', interactive, rl);
101
+ const languagesInput = await resolve(opts, 'languages', 'Enter the languages (2-letter codes) separated by commas:\n', interactive, rl);
102
+ const fcmSenderId = await resolve(opts, 'fcmSenderId', 'Enter the FCMSenderId value (see https://xsites.atlassian.net/wiki/spaces/IKB/pages/777650347/Onboarding+Branding+Manual+for+devs#Firebase): ', interactive, rl);
103
+ const typeInput = await resolve(opts, 'type', `Enter the type value (allowed values: ${ALLOWED_TYPES.join(', ')}): `, interactive, rl);
104
+
105
+ // baseUrl is optional (defaults to the dev URL).
106
+ const baseUrl = opts.baseUrl !== undefined && opts.baseUrl !== ''
107
+ ? opts.baseUrl
108
+ : (interactive ? (await ask(rl, `Enter the configs.ts baseUrl (leave empty for ${DEFAULT_BASE_URL}):\n`)) || DEFAULT_BASE_URL : DEFAULT_BASE_URL);
109
+
110
+ // Validate required fields.
111
+ const missing = [];
112
+ if (!connectedBrandName) missing.push('--brand_id');
113
+ if (!brandName) missing.push('--brand_name');
114
+ if (!logo) missing.push('--logo_url');
115
+ if (!favicon) missing.push('--favicon_url');
116
+ if (!languagesInput) missing.push('--languages');
117
+ if (!fcmSenderId) missing.push('--fcm_sender_id');
118
+ if (!typeInput) missing.push('--type');
119
+ if (missing.length) {
120
+ console.error(chalk.red(`Error: missing required value(s): ${missing.join(', ')}`));
121
+ console.log(HELP);
122
+ process.exitCode = 1;
123
+ return;
124
+ }
125
+
126
+ const type = typeInput.toUpperCase();
127
+ if (!ALLOWED_TYPES.includes(type)) {
128
+ console.error(chalk.red(`Error: invalid --type "${typeInput}". Allowed: ${ALLOWED_TYPES.join(', ')}`));
129
+ process.exitCode = 1;
130
+ return;
131
+ }
132
+
133
+ const languages = languagesInput.trim().split(',').map((l) => l.trim()).filter(Boolean);
134
+ if (!languages.length) {
135
+ console.error(chalk.red('Error: --languages must contain at least one 2-letter code.'));
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+
140
+ brandModule.updateBrand({
141
+ brandId: connectedBrandName,
142
+ brandName,
143
+ connectedBrandName,
144
+ color: color || '',
145
+ logo,
146
+ languages,
147
+ favicon,
148
+ FCMSenderId: fcmSenderId,
149
+ type,
150
+ baseUrl
151
+ });
152
+
153
+ console.log(chalk.bold(chalk.yellow(`\nOnboarding "${brandName}" (id: ${connectedBrandName})`)));
154
+ console.log(chalk.bold(chalk.yellow('\nStep 1: Add to variables-colors.scss')));
155
+ await variablesColors.start();
156
+ console.log(chalk.bold(chalk.yellow('\nStep 2: Add to themes.scss')));
157
+ await themes.start();
158
+ console.log(chalk.bold(chalk.yellow('\nStep 3: Adding translations')));
159
+ await translations.start();
160
+ console.log(chalk.bold(chalk.yellow('\nStep 4: Editing the config file')));
161
+ await createConfig.start();
162
+ console.log(chalk.bold(chalk.yellow('\nStep 5: Registering the logo in brand-logos.json')));
163
+ await brandLogos.start();
164
+ console.log(chalk.bold(chalk.yellow('\nStep 6: Recording in BRAND_LOCATIONS.md')));
165
+ await brandLocations.start();
166
+ console.log(chalk.green('\nCRM onboarding completed!'));
167
+ } catch (err) {
168
+ console.error(chalk.red(err) + '\n Please delete files and code added by this failed session.');
169
+ process.exitCode = 1;
170
+ } finally {
171
+ if (rl) rl.close();
172
+ }
173
+ }
174
+
175
+ run();
@@ -1,92 +1,92 @@
1
- const fs = require('fs');
2
- const brandModule = require('./brand.js');
3
- const chalk = require('chalk');
4
- const themesPath = 'src/ng1/assets/css/sass/materialism/themes.scss';
5
-
6
- function addColorToMap(mapName, key, value, data) {
7
- const mapRegex = new RegExp(`\\$${mapName}:\\s*\\(([\\s\\S]*?)\\)`);
8
- const match = data.match(mapRegex);
9
- if (match) {
10
- const mapContent = match[1];
11
- const newMapContent = `$${mapName}: (${mapContent.replace(/\s*$/, '')},\n '${key}': ${value}\n)`;
12
- data = data.replace(mapRegex, newMapContent);
13
- } else {
14
- throw new Error(`Error: Could not find ${mapName} map in the file`);
15
- }
16
- return data;
17
- }
18
-
19
- // Same edits as onboarding/themes.js, driven by resolved brand state (no prompts).
20
- function start() {
21
- const brand = brandModule.getBrand();
22
- return new Promise((resolve, reject) => {
23
- const themeVar = `
24
- .theme-template-${brand.connectedBrandName} {
25
- #logo {
26
- display: inline-block;
27
- width: 240px;
28
- height: 120px;
29
- background: url('${brand.logo}') no-repeat center center;
30
- background-size: contain;
31
- }
32
- .navbar-toggle-container {
33
- background: #222C38;
34
-
35
- .icon-bar {
36
- background: #fff !important;
37
- }
38
- }
39
- .sidebar {
40
- background: #222C38;
41
- color: #ffffff;
42
-
43
- ul a,
44
- i {
45
- color: #ffffff;
46
- }
47
-
48
- .brand-logo,
49
- .brand-logo-text {
50
- display: none;
51
- }
52
- .user-logged-in:after {
53
- background: #26303C;
54
- }
55
- }
56
- }
57
- \n`;
58
- fs.readFile(themesPath, 'utf8', (err, data) => {
59
- if (err) {
60
- return reject(err);
61
- }
62
- try {
63
- data = addColorToMap(
64
- 'theme-colors',
65
- brand.connectedBrandName,
66
- brand.color ? `$${brand.connectedBrandName}` : '$corp',
67
- data
68
- );
69
- data = addColorToMap(
70
- 'theme-secondary-colors',
71
- brand.connectedBrandName,
72
- brand.color ? `'${brand.connectedBrandName}'` : "'corp'",
73
- data
74
- );
75
- } catch (mapError) {
76
- return reject(mapError);
77
- }
78
- const insertionPoint = data.lastIndexOf('@each $color-name');
79
- const newFileContent = data.slice(0, insertionPoint) + themeVar + data.slice(insertionPoint);
80
- fs.writeFile(themesPath, newFileContent, 'utf8', (error) => {
81
- if (error) {
82
- reject(error);
83
- } else {
84
- console.log(chalk.cyan('themes.scss file updated successfully!'));
85
- resolve(null);
86
- }
87
- });
88
- });
89
- });
90
- }
91
-
92
- module.exports = { start };
1
+ const fs = require('fs');
2
+ const brandModule = require('./brand.js');
3
+ const chalk = require('chalk');
4
+ const themesPath = 'src/ng1/assets/css/sass/materialism/themes.scss';
5
+
6
+ function addColorToMap(mapName, key, value, data) {
7
+ const mapRegex = new RegExp(`\\$${mapName}:\\s*\\(([\\s\\S]*?)\\)`);
8
+ const match = data.match(mapRegex);
9
+ if (match) {
10
+ const mapContent = match[1];
11
+ const newMapContent = `$${mapName}: (${mapContent.replace(/\s*$/, '')},\n '${key}': ${value}\n)`;
12
+ data = data.replace(mapRegex, newMapContent);
13
+ } else {
14
+ throw new Error(`Error: Could not find ${mapName} map in the file`);
15
+ }
16
+ return data;
17
+ }
18
+
19
+ // Same edits as onboarding/themes.js, driven by resolved brand state (no prompts).
20
+ function start() {
21
+ const brand = brandModule.getBrand();
22
+ return new Promise((resolve, reject) => {
23
+ const themeVar = `
24
+ .theme-template-${brand.connectedBrandName} {
25
+ #logo {
26
+ display: inline-block;
27
+ width: 240px;
28
+ height: 120px;
29
+ background: url('${brand.logo}') no-repeat center center;
30
+ background-size: contain;
31
+ }
32
+ .navbar-toggle-container {
33
+ background: #222C38;
34
+
35
+ .icon-bar {
36
+ background: #fff !important;
37
+ }
38
+ }
39
+ .sidebar {
40
+ background: #222C38;
41
+ color: #ffffff;
42
+
43
+ ul a,
44
+ i {
45
+ color: #ffffff;
46
+ }
47
+
48
+ .brand-logo,
49
+ .brand-logo-text {
50
+ display: none;
51
+ }
52
+ .user-logged-in:after {
53
+ background: #26303C;
54
+ }
55
+ }
56
+ }
57
+ \n`;
58
+ fs.readFile(themesPath, 'utf8', (err, data) => {
59
+ if (err) {
60
+ return reject(err);
61
+ }
62
+ try {
63
+ data = addColorToMap(
64
+ 'theme-colors',
65
+ brand.connectedBrandName,
66
+ brand.color ? `$${brand.connectedBrandName}` : '$corp',
67
+ data
68
+ );
69
+ data = addColorToMap(
70
+ 'theme-secondary-colors',
71
+ brand.connectedBrandName,
72
+ brand.color ? `'${brand.connectedBrandName}'` : "'corp'",
73
+ data
74
+ );
75
+ } catch (mapError) {
76
+ return reject(mapError);
77
+ }
78
+ const insertionPoint = data.lastIndexOf('@each $color-name');
79
+ const newFileContent = data.slice(0, insertionPoint) + themeVar + data.slice(insertionPoint);
80
+ fs.writeFile(themesPath, newFileContent, 'utf8', (error) => {
81
+ if (error) {
82
+ reject(error);
83
+ } else {
84
+ console.log(chalk.cyan('themes.scss file updated successfully!'));
85
+ resolve(null);
86
+ }
87
+ });
88
+ });
89
+ });
90
+ }
91
+
92
+ module.exports = { start };