solara 0.4.0 → 0.5.0

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/solara/lib/.DS_Store +0 -0
  3. data/solara/lib/core/.DS_Store +0 -0
  4. data/solara/lib/core/brands/brand_switcher.rb +58 -1
  5. data/solara/lib/core/dashboard/brand/BrandDetail.js +34 -2
  6. data/solara/lib/core/dashboard/brand/BrandDetailController.js +23 -233
  7. data/solara/lib/core/dashboard/brand/BrandDetailModel.js +13 -5
  8. data/solara/lib/core/dashboard/brand/BrandDetailView.js +16 -200
  9. data/solara/lib/core/dashboard/brand/SectionsFormManager.js +232 -0
  10. data/solara/lib/core/dashboard/brand/brand.html +187 -177
  11. data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +2 -5
  12. data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +36 -133
  13. data/solara/lib/core/dashboard/brands/Brands.js +31 -0
  14. data/solara/lib/core/dashboard/brands/BrandsController.js +0 -5
  15. data/solara/lib/core/dashboard/brands/BrandsView.js +2 -2
  16. data/solara/lib/core/dashboard/brands/brands.html +71 -52
  17. data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +6 -6
  18. data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +4 -4
  19. data/solara/lib/core/dashboard/component/ConfirmationDialog.js +15 -10
  20. data/solara/lib/core/dashboard/component/EditJsonSheet.js +160 -0
  21. data/solara/lib/core/dashboard/component/MessageBottomSheet.js +5 -5
  22. data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +5 -3
  23. data/solara/lib/core/dashboard/handler/base_handler.rb +1 -0
  24. data/solara/lib/core/dashboard/handler/edit_section_handler.rb +1 -5
  25. data/solara/lib/core/doctor/schema/brand_configurations.json +0 -8
  26. data/solara/lib/core/doctor/schema/platform/global/resources_manifest.json +30 -0
  27. data/solara/lib/core/doctor/schema/platform/json_manifest.json +57 -0
  28. data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +35 -1
  29. data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +30 -1
  30. data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +35 -1
  31. data/solara/lib/core/doctor/validator/template/template_validator.rb +9 -9
  32. data/solara/lib/core/scripts/brand_config_manager.rb +1 -1
  33. data/solara/lib/core/scripts/brand_configurations_manager.rb +41 -0
  34. data/solara/lib/core/scripts/code_generator.rb +342 -118
  35. data/solara/lib/core/scripts/file_path.rb +21 -1
  36. data/solara/lib/core/scripts/gitignore_manager.rb +11 -3
  37. data/solara/lib/core/scripts/json_manifest_processor.rb +95 -0
  38. data/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +11 -1
  39. data/solara/lib/core/scripts/resource_manifest_processor.rb +151 -0
  40. data/solara/lib/core/scripts/solara_status_manager.rb +1 -1
  41. data/solara/lib/core/scripts/theme_generator.rb +21 -242
  42. data/solara/lib/core/solara_configurator.rb +1 -1
  43. data/solara/lib/core/template/brands/global/resources_manifest.json +10 -0
  44. data/solara/lib/core/template/brands/json/Json-Manifest.md +61 -0
  45. data/solara/lib/core/template/brands/json/json_manifest.json +18 -0
  46. data/solara/lib/core/template/brands/shared/theme.json +213 -29
  47. data/solara/lib/core/template/config/android_template_config.json +50 -0
  48. data/solara/lib/core/template/config/flutter_template_config.json +35 -0
  49. data/solara/lib/core/template/config/ios_template_config.json +50 -0
  50. data/solara/lib/core/template/configurations.json +46 -0
  51. data/solara/lib/core/template/project_template_generator.rb +2 -0
  52. data/solara/lib/solara/version.rb +1 -1
  53. data/solara/lib/solara.rb +19 -0
  54. metadata +13 -4
  55. data/solara/lib/core/dashboard/component/AddFieldSheet.js +0 -175
  56. data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +0 -73
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b672162bbb4a247a016626afacc37b2deaab1dbde0c2f86e30a4ceedeb8a635d
4
- data.tar.gz: a0e53ed9ce61d791a50df3c292b1c096414903e7c573164e7553089048f289cc
3
+ metadata.gz: 714797cd507e354e49c4a1981a516f6ad3e659797ba40b6040c7e7a6f30f11aa
4
+ data.tar.gz: 3b3d4ed6c116abea9dd15c2db4b5df308320649be4381623e3c7a3c863ef0385
5
5
  SHA512:
6
- metadata.gz: a22345201f6d5756cc2a54702dc8a0db0806d4fd1fd47f9f85dfde81545368908d22408345dae944bc004c4fe3507ceef563e6044cf7a90daad5a157efb1295f
7
- data.tar.gz: be3473d1802240cf75b4f934561e22302cbf93dee710dead6c0439b474e3b7c16ca858f3b647e480e04a493622ce9b8da488135179bca97caa808feedd1b2b18
6
+ metadata.gz: b4c46c3f893d95eddbde530e7d83fe340ce36698974880073b3517779bb8e39b31813863c13f7743e821936b814e6d7f5d42337c10b3ef37a4cd6767732f5a20
7
+ data.tar.gz: 750e7851fa9584bb85b00b5f01e48ea246892914f1bbfafeb7a2b18db8e138d0da5f8fd2a2253434bed1dd6b6d9b0c6911dcaec908714e96ff69c894653490b8
data/solara/lib/.DS_Store CHANGED
Binary file
Binary file
@@ -30,6 +30,9 @@ class BrandSwitcher
30
30
  def switch
31
31
  BrandFontSwitcher.new(@brand_key).switch
32
32
 
33
+ ResourceManifestSwitcher.new(@brand_key).switch
34
+ JsonManifestSwitcher.new(@brand_key).switch
35
+
33
36
  case @platform
34
37
  when Platform::Flutter
35
38
  IOSBrandSwitcher.new(@brand_key).switch
@@ -42,6 +45,60 @@ class BrandSwitcher
42
45
  else
43
46
  raise ArgumentError, "Invalid platform: #{@platform}"
44
47
  end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ class ResourceManifestSwitcher
54
+ def initialize(brand_key)
55
+ @brand_key = brand_key
56
+ end
57
+
58
+ def switch
59
+ Solara.logger.start_step("Process resource manifest: #{FilePath.resources_manifest}")
60
+ brand_resource_copier = ResourceManifestProcessor.new(@brand_key)
61
+ brand_resource_copier.copy
62
+ Solara.logger.debug("#{@brand_key} resources copied successfully according to the manifest: #{FilePath.resources_manifest}.")
63
+ Solara.logger.end_step("Process resource manifest: #{FilePath.resources_manifest}")
64
+ end
65
+
66
+ end
67
+
68
+ class JsonManifestSwitcher
69
+ def initialize(brand_key)
70
+ @brand_key = brand_key
71
+ @manifest_path = FilePath.brand_json_dir(brand_key)
72
+ end
73
+
74
+ def switch
75
+ Solara.logger.start_step("Process JSON manifest: #{@manifest_path}")
76
+
77
+
78
+ case SolaraSettingsManager.instance.platform
79
+ when Platform::Flutter
80
+ process_maifest(Language::Dart, FilePath.flutter_lib_artifacts)
81
+ process_maifest(Language::Dart, FilePath.brand_global_json_dir)
82
+ when Platform::IOS
83
+ process_maifest(Language::Swift, FilePath.ios_project_root_artifacts)
84
+ process_maifest(Language::Swift, FilePath.brand_global_json_dir)
85
+ when Platform::Android
86
+ process_maifest(Language::Kotlin, FilePath.android_project_java_artifacts )
87
+ process_maifest(Language::Kotlin, FilePath.brand_global_json_dir)
88
+ else
89
+ raise ArgumentError, "Invalid platform: #{@platform}"
90
+ end
91
+
92
+ Solara.logger.end_step("Process JSON manifest: #{@manifest_path}")
93
+ end
94
+
95
+ def process_maifest(language, output_path)
96
+ processor = JsonManifestProcessor.new(
97
+ @manifest_path,
98
+ language,
99
+ output_path
100
+ )
101
+ processor.process
45
102
  end
46
103
  end
47
104
 
@@ -225,7 +282,7 @@ class ThemeSwitcher
225
282
  def generate_theme(name, language, platform)
226
283
  Solara.logger.start_step("Generate #{name} for #{platform}")
227
284
 
228
- theme_manager = ThemeGeneratorManager.new(FilePath.brand_theme(@brand_key))
285
+ theme_manager = ThemeGenerator.new(FilePath.brand_theme(@brand_key))
229
286
  theme_manager.generate(language, FilePath.generated_config(name, platform))
230
287
 
231
288
  Solara.logger.end_step("Generate #{name} for #{platform}")
@@ -2,6 +2,37 @@ import BrandDetailModel from './BrandDetailModel.js';
2
2
  import BrandDetailView from './BrandDetailView.js';
3
3
  import BrandDetailController from './BrandDetailController.js';
4
4
 
5
+ const modeToggle = document.getElementById('modeToggle');
6
+ const body = document.body;
7
+ const icon = modeToggle.querySelector('i');
8
+
9
+ function applyMode(mode) {
10
+ if (mode === 'dark') {
11
+ body.classList.add('dark-mode');
12
+ icon.classList.remove('fa-sun');
13
+ icon.classList.add('fa-moon');
14
+ } else {
15
+ body.classList.remove('dark-mode');
16
+ icon.classList.remove('fa-moon');
17
+ icon.classList.add('fa-sun');
18
+ }
19
+ }
20
+
21
+ const savedMode = localStorage.getItem('mode');
22
+ if (savedMode) {
23
+ applyMode(savedMode);
24
+ } else {
25
+ const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
26
+ applyMode(systemPrefersDark ? 'dark' : 'light');
27
+ }
28
+
29
+ modeToggle.addEventListener('click', () => {
30
+ const currentMode = body.classList.contains('dark-mode') ? 'dark' : 'light';
31
+ const newMode = currentMode === 'dark' ? 'light' : 'dark';
32
+ applyMode(newMode);
33
+ localStorage.setItem('mode', newMode);
34
+ });
35
+
5
36
  window.onload = function () {
6
37
  document.getElementById('loadingOverlay').style.display = 'none';
7
38
  };
@@ -20,10 +51,11 @@ window.addEventListener('scroll', function () {
20
51
  }
21
52
  lastScrollTop = scrollTop;
22
53
  });
23
-
54
+
24
55
  document.addEventListener('DOMContentLoaded', async () => {
25
56
  const model = new BrandDetailModel();
26
57
  const view = new BrandDetailView(model);
27
58
  const controller = new BrandDetailController(model, view);
28
59
  await controller.initializeApp();
29
- });
60
+ });
61
+
@@ -1,15 +1,10 @@
1
1
  import {DataSource} from './BrandDetailModel.js';
2
- import InfoPlistStringCatalogManager from "./InfoPlistStringCatalogManager.js";
3
2
 
4
3
  class BrandDetailController {
5
4
  constructor(model, view) {
6
5
  this.model = model;
7
6
  this.view = view;
8
- this.onSectionChanged = this.onSectionChanged.bind(this);
9
- this.deleteField = this.deleteField.bind(this);
10
7
  this.initializeEventListeners();
11
- this.view.setOnSectionChangedHandler(this.onSectionChanged.bind(this));
12
- this.view.setOnDeleteFieldHandler(this.deleteField.bind(this));
13
8
  }
14
9
 
15
10
  async initializeApp() {
@@ -80,7 +75,7 @@ class BrandDetailController {
80
75
 
81
76
  async addNewBrand() {
82
77
  this.view.showOnboardBrandForm(async (key, name) => {
83
- const configurations = await this.model.createNewBrandConfogurations()
78
+ const configurations = await this.model.createNewBrandConfigurations()
84
79
  await this.addBrand(key, name, configurations)
85
80
  })
86
81
  }
@@ -97,10 +92,10 @@ class BrandDetailController {
97
92
  await this.onLoadSections(response.result);
98
93
  const {isCurrentBrand, contentChanged} = await this.model.fetchCurrentBrand();
99
94
 
100
- if (!isCurrentBrand) {
95
+ if (isCurrentBrand) {
96
+ this.view.setupSyncBrandButton(contentChanged ? '#ff4136' : '#4A90E2');
97
+ } else {
101
98
  this.view.showSwitchButton();
102
- } else if (contentChanged) {
103
- this.view.showApplyChangesButton();
104
99
  }
105
100
 
106
101
  await this.checkBrandHealth();
@@ -128,7 +123,12 @@ class BrandDetailController {
128
123
  window.location.href = `../brands/brands.html?source=${this.model.source}`;
129
124
  });
130
125
 
131
- document.getElementById('applyChangesButton').addEventListener('click', () => this.switchToBrand());
126
+ document.getElementById('syncBrandButton').addEventListener(
127
+ 'click',
128
+ async () => {
129
+ await this.switchToBrand()
130
+ await this.view.toast("Synced successfully")
131
+ });
132
132
  document.getElementById('switchButton').addEventListener('click', () => this.switchToBrand());
133
133
 
134
134
  this.view.exportBrandBtn.addEventListener('click', () => this.exportBrand());
@@ -141,188 +141,37 @@ class BrandDetailController {
141
141
 
142
142
  const sectionItems = configuraationsResult.configurations
143
143
 
144
- for (let i = 0; i < sectionItems.length; i++) {
145
- const sectionData = sectionItems[i];
146
-
147
- if (sectionData.key === 'theme.json') {
148
- this.createThemeSections(sectionData)
149
- } else if (sectionData.key === 'InfoPlist.xcstrings') {
150
- this.createSection(
151
- sectionData.key,
152
- sectionData,
153
- new InfoPlistStringCatalogManager(sectionData.content).extractLocalizations(),
154
- sectionData.name,
155
- sectionData.inputType)
156
- } else {
157
- this.createSection(sectionData.key, sectionData, sectionData.content, sectionData.name, sectionData.inputType)
158
- }
159
- }
144
+ this.view.sectionsFormManager.display(
145
+ sectionItems,
146
+ (section, container) => {
147
+ this.onSectionChanged(section, container)
148
+ })
149
+
160
150
  } catch (error) {
161
151
  console.error('Error loading configurations:', error);
162
152
  alert(error.message);
163
153
  }
164
154
  }
165
155
 
166
- createThemeSections(sectionData) {
167
- this.createSection(`${sectionData.key}_colors`,
168
- sectionData,
169
- sectionData.content.colors,
170
- 'Theme Colors',
171
- 'color',
172
- 'colors')
173
- this.createSection(`${sectionData.key}_typography`,
174
- sectionData,
175
- sectionData.content.typography,
176
- 'Theme Typography',
177
- 'text',
178
- 'typography')
179
- this.createSection(`${sectionData.key}_spacing`,
180
- sectionData,
181
- sectionData.content.spacing,
182
- 'Theme Spacing', 'text',
183
- 'spacing')
184
- this.createSection(
185
- `${sectionData.key}_borderRadius`,
186
- sectionData,
187
- sectionData.content.borderRadius,
188
- 'Theme Border Radius',
189
- 'text',
190
- 'borderRadius')
191
- this.createSection(
192
- `${sectionData.key}_elevation`,
193
- sectionData,
194
- sectionData.content.elevation,
195
- 'Theme Elevation',
196
- 'text',
197
- 'elevation')
198
- }
199
-
200
- createSection(id, sectionData, content, sectionName, inputType, propertiesGroupName = null) {
201
- const sectionElement = this.view.createSection(sectionData.key, sectionName, inputType);
202
- sectionElement.id = id;
203
- sectionElement.dataset.propertiesGroupName = propertiesGroupName
204
-
205
- this.view.sectionsContainer.appendChild(sectionElement);
206
-
207
- this.view.populateJsonFields(sectionData, sectionElement, content, inputType);
156
+ async onSectionChanged(section, container) {
157
+ if (this.model.isRemote()) return
208
158
 
209
- const addButton = document.createElement('button');
210
- addButton.textContent = 'Add Field';
211
- addButton.className = 'add-field-btn';
212
- addButton.onclick = () => this.addNewField(sectionData, sectionElement, inputType);
213
- sectionElement.appendChild(addButton);
214
- }
215
-
216
- async onSectionChanged(sectionItem, sectionElement) {
217
159
  try {
218
- const configuration = await this.getSectionData(sectionElement.dataset.key)
219
- await this.model.saveSection(sectionItem, configuration);
220
- this.view.showApplyChangesButton();
160
+ await this.model.saveSection(container.dataset.key, section.content);
221
161
  await this.checkBrandHealth();
162
+ await this.switchToBrand(true)
222
163
  } catch (error) {
223
164
  console.error('Error saving section:', error);
224
165
  alert(error.message);
225
166
  }
226
167
  }
227
168
 
228
- collectJsonData(container) {
229
- const data = {};
230
- const level = container.dataset.level
231
-
232
- const jsonObjects = container.querySelectorAll(`.json-object-${level}`);
233
- jsonObjects.forEach(jsonObject => {
234
- const jsonObjectLabel = jsonObject.querySelector('label').textContent;
235
- data[jsonObjectLabel] = this.collectJsonData(jsonObject);
236
-
237
- });
238
-
239
- const group = container.querySelectorAll(`.json-array-${level}`);
240
- group.forEach(arrayItem => {
241
- const label = arrayItem.querySelector('label').textContent;
242
- const items = arrayItem.querySelectorAll(`.json-array-item-${level}`);
243
- const indexed = arrayItem.querySelectorAll(`.json-array-item-indexed-${level}`).length !== 0;
244
-
245
- data[label] = Array.from(items).map((item, index) => {
246
- const values = this.collectJsonData(item)
247
- if (indexed) {
248
- return values[index]
249
- }
250
- return values;
251
- });
252
- });
253
-
254
- const result = this.collectJsonFields(container, level);
255
-
256
- Object.keys(data).forEach(key => {
257
- result[key] = data[key];
258
- });
259
- return result
260
- }
261
-
262
- collectJsonFields(container, level) {
263
- const result = {};
264
-
265
- const inputFields = container.querySelectorAll(`.json-field-${level}`);
266
- inputFields.forEach(inputField => {
267
- const values = this.getInputFieldsData(inputField);
268
- Object.keys(values).forEach(key => {
269
- result[key] = values[key];
270
- });
271
- })
272
- return result
273
- }
274
-
275
- getInputFieldsData(container) {
276
- const data = {};
277
-
278
- const inputs = container.querySelectorAll('input');
279
- inputs.forEach(input => {
280
- if (input.type === 'checkbox') {
281
- data[input.id] = input.checked;
282
- } else {
283
- let value = input.value;
284
- if (input.type === 'color') {
285
- value = `#${value.substring(1).toUpperCase()}`;
286
- } else if (!isNaN(value) && value.trim() !== '') {
287
- // Convert to number if it's a valid number string
288
- value = parseFloat(value);
289
- }
290
- data[input.id] = value;
291
- }
292
- });
293
-
294
- return data;
295
- }
296
-
297
- addNewField(sectionItem, sectionElement, inputType) {
298
- this.view.showAddFieldForm(sectionItem, sectionElement, inputType);
299
- }
300
-
301
- deleteField(sectionItem, fieldContainer) {
302
- this.view.showConfirmationDialog(
303
- 'Are you sure you want to delete this item?',
304
- () => {
305
- const sectionElement = fieldContainer.closest('.section');
306
- fieldContainer.remove();
307
- this.onSectionChanged(sectionItem, sectionElement);
308
- }
309
- );
310
- }
311
-
312
- getArrayValue(container) {
313
- const arrayItems = container.querySelectorAll('.array-item-input');
314
- return Array.from(arrayItems).map(item => item.value);
315
- }
316
-
317
- async switchToBrand() {
169
+ async switchToBrand(silentError = false) {
318
170
  try {
319
171
  await this.model.switchToBrand();
320
- const applyChangesButton = document.getElementById('applyChangesButton');
321
- applyChangesButton.style.display = 'none';
322
- location.reload();
323
172
  } catch (error) {
324
173
  console.error('Error switching to brand:', error);
325
- alert(error.message);
174
+ if (!silentError) alert(error.message);
326
175
  }
327
176
  }
328
177
 
@@ -350,72 +199,13 @@ class BrandDetailController {
350
199
  }
351
200
  }
352
201
 
353
- async getSectionData(sectionKey) {
354
- try {
355
- const container = this.view.sectionsContainer;
356
-
357
- const sectionElements = Array.from(container.querySelectorAll('.section'))
358
- .filter(element => element.dataset.key === sectionKey);
359
-
360
- if (sectionElements.length === 1) {
361
- return this.collectJsonData(sectionElements[0])
362
- }
363
-
364
- const configurations = sectionElements.map(sectionElement => {
365
- const propertiesGroupName = sectionElement.dataset.propertiesGroupName;
366
- const config = this.collectJsonData(sectionElement);
367
-
368
- if (propertiesGroupName !== "null") {
369
- return {[propertiesGroupName]: config};
370
- } else {
371
- return config;
372
- }
373
- });
374
-
375
- return configurations.reduce((acc, config) => {
376
- const key = Object.keys(config)[0]; // Get the key from the configuration item
377
- acc[key] = config[key]; // Assign the value to the dynamic object
378
- return acc;
379
- }, {});
380
-
381
- } catch (error) {
382
- console.error('Error downloading brand:', error);
383
- alert(error.message);
384
- }
385
- }
386
-
387
202
  async exportBrand() {
388
203
  try {
389
- const sectionsContainer = this.view.sectionsContainer;
204
+ const result = this.view.sectionsFormManager.data();
390
205
 
391
206
  const brandKey = this.view.sectionsContainer.dataset.brandKey;
392
207
  const brandName = this.view.sectionsContainer.dataset.brandName;
393
208
 
394
- const sectionElements = Array.from(sectionsContainer.querySelectorAll('.section'));
395
-
396
- const uniqueSections = new Map();
397
-
398
- // The theme section has been divided into multiple categories (e.g., colors, typography).
399
- // In the getSectionData function, we merge these sections. To prevent duplication when
400
- // processing the sections, we will ensure that each section key is processed only once.
401
- await Promise.all(sectionElements.map(async sectionElement => {
402
- const key = sectionElement.dataset.key;
403
- // Check if the key already exists in the map
404
- if (!uniqueSections.has(key)) {
405
- const configurations = await this.getSectionData(key);
406
- uniqueSections.set(
407
- key, {
408
- key: key,
409
- name: sectionElement.dataset.name,
410
- inputType: sectionElement.dataset.inputType,
411
- content: configurations
412
- });
413
- }
414
- }));
415
-
416
- // Convert the map values to an array
417
- const result = Array.from(uniqueSections.values());
418
-
419
209
  this.model.exportBrand(brandKey, brandName, result);
420
210
 
421
211
  } catch (error) {
@@ -17,6 +17,14 @@ class BrandDetailModel {
17
17
  this.source = sourceFromUrl === DataSource.LOCAL ? DataSource.LOCAL : DataSource.REMOTE;
18
18
  }
19
19
 
20
+ isLocal() {
21
+ return this.source === DataSource.LOCAL
22
+ }
23
+
24
+ isRemote() {
25
+ return this.source === DataSource.REMOTE
26
+ }
27
+
20
28
  getQueryFromUrl(name) {
21
29
  return this.localSource.getQueryFromUrl(name);
22
30
  }
@@ -29,10 +37,10 @@ class BrandDetailModel {
29
37
  return await this.localSource.fetchCurrentBrand(this.brandKey);
30
38
  }
31
39
 
32
- async saveSection(sectionItem, configuration) {
40
+ async saveSection(key, configuration) {
33
41
  switch (this.source) {
34
42
  case DataSource.LOCAL:
35
- return await this.localSource.saveSection(sectionItem, configuration, this.brandKey);
43
+ return await this.localSource.saveSection(key, configuration, this.brandKey);
36
44
  case DataSource.REMOTE:
37
45
  // Saving is not supported remotely. Instead, user can export the brand.
38
46
  return
@@ -48,7 +56,7 @@ class BrandDetailModel {
48
56
  async checkBrandHealth() {
49
57
  switch (this.source) {
50
58
  case DataSource.LOCAL:
51
- return await this.localSource.checkBrandHealth(this.brandKey);
59
+ return await this.localSource.checkBrandHealth(this.brandKey);
52
60
  case DataSource.REMOTE:
53
61
  // Checking health is not supported remotely yet.
54
62
  return
@@ -57,8 +65,8 @@ class BrandDetailModel {
57
65
  }
58
66
  }
59
67
 
60
- async createNewBrandConfogurations() {
61
- return await this.remoteSource.createNewBrandConfogurations();
68
+ async createNewBrandConfigurations() {
69
+ return await this.remoteSource.createNewBrandConfigurations();
62
70
  }
63
71
 
64
72
  async createBrandConfigurationsFromDirectory(dirHandle) {