solara 0.1.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.
- checksums.yaml +7 -0
- data/bin/solara +18 -0
- data/solara/lib/.DS_Store +0 -0
- data/solara/lib/core/.DS_Store +0 -0
- data/solara/lib/core/aliases/alias_generator.rb +128 -0
- data/solara/lib/core/aliases/alias_generator_manager.rb +28 -0
- data/solara/lib/core/aliases/solara_terminal_setup.rb +103 -0
- data/solara/lib/core/brands/brand_onboarder.rb +46 -0
- data/solara/lib/core/brands/brand_switcher.rb +204 -0
- data/solara/lib/core/brands/brands_manager.rb +154 -0
- data/solara/lib/core/dashboard/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/.DS_Store +0 -0
- data/solara/lib/core/dashboard/brand/BrandDetail.js +11 -0
- data/solara/lib/core/dashboard/brand/BrandDetailController.js +361 -0
- data/solara/lib/core/dashboard/brand/BrandDetailModel.js +155 -0
- data/solara/lib/core/dashboard/brand/BrandDetailView.js +245 -0
- data/solara/lib/core/dashboard/brand/brand.html +477 -0
- data/solara/lib/core/dashboard/brand/source/BrandLocalSource.js +123 -0
- data/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +260 -0
- data/solara/lib/core/dashboard/brands/Brands.js +10 -0
- data/solara/lib/core/dashboard/brands/BrandsController.js +155 -0
- data/solara/lib/core/dashboard/brands/BrandsModel.js +136 -0
- data/solara/lib/core/dashboard/brands/BrandsView.js +136 -0
- data/solara/lib/core/dashboard/brands/brands.html +345 -0
- data/solara/lib/core/dashboard/component/AddFieldSheet.js +212 -0
- data/solara/lib/core/dashboard/component/AliasesBottomSheet.js +128 -0
- data/solara/lib/core/dashboard/component/BrandOptionsBottomSheet.js +130 -0
- data/solara/lib/core/dashboard/component/ConfirmationDialog.js +103 -0
- data/solara/lib/core/dashboard/component/MessageBottomSheet.js +80 -0
- data/solara/lib/core/dashboard/component/OnboardBrandBottomSheet.js +214 -0
- data/solara/lib/core/dashboard/dashboard_manager.rb +19 -0
- data/solara/lib/core/dashboard/dashboard_server.rb +132 -0
- data/solara/lib/core/dashboard/handler/base_handler.rb +25 -0
- data/solara/lib/core/dashboard/handler/brand_alisases_handler.rb +33 -0
- data/solara/lib/core/dashboard/handler/brand_configurations_handler.rb +18 -0
- data/solara/lib/core/dashboard/handler/brand_configurations_manager.rb +73 -0
- data/solara/lib/core/dashboard/handler/brand_icon_handler.rb +20 -0
- data/solara/lib/core/dashboard/handler/brand_section_handler.rb +20 -0
- data/solara/lib/core/dashboard/handler/brands_handler.rb +14 -0
- data/solara/lib/core/dashboard/handler/current_brand_handler.rb +18 -0
- data/solara/lib/core/dashboard/handler/doctor_handler.rb +39 -0
- data/solara/lib/core/dashboard/handler/edit_section_handler.rb +55 -0
- data/solara/lib/core/dashboard/handler/offboard_brand_handler.rb +34 -0
- data/solara/lib/core/dashboard/handler/onboard_brand_handler.rb +53 -0
- data/solara/lib/core/dashboard/handler/redirect_handler.rb +12 -0
- data/solara/lib/core/dashboard/handler/switch_handler.rb +25 -0
- data/solara/lib/core/dashboard/index.html +36 -0
- data/solara/lib/core/dashboard/local.html +41 -0
- data/solara/lib/core/dashboard/res/favicon/android-chrome-192x192.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/android-chrome-512x512.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/apple-touch-icon.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon-16x16.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon-32x32.png +0 -0
- data/solara/lib/core/dashboard/res/favicon/favicon.ico +0 -0
- data/solara/lib/core/dashboard/res/favicon/site.webmanifest +1 -0
- data/solara/lib/core/dashboard/solara.png +0 -0
- data/solara/lib/core/doctor/brand_doctor.rb +94 -0
- data/solara/lib/core/doctor/doctor_manager.rb +35 -0
- data/solara/lib/core/doctor/project_doctor.rb +8 -0
- data/solara/lib/core/doctor/schema/brand_configurations.json +60 -0
- data/solara/lib/core/doctor/schema/platform/android/android_config.json +23 -0
- data/solara/lib/core/doctor/schema/platform/android/android_signing.json +23 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_config.json +27 -0
- data/solara/lib/core/doctor/schema/platform/ios/ios_signing.json +27 -0
- data/solara/lib/core/doctor/schema/platform/shared/theme.json +48 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator.rb +55 -0
- data/solara/lib/core/doctor/validator/brand_settings_validator_manager.rb +82 -0
- data/solara/lib/core/doctor/validator/directory_structure_validator.rb +38 -0
- data/solara/lib/core/doctor/validator/file_structure_validator.rb +37 -0
- data/solara/lib/core/doctor/validator/json_file_validator.rb +21 -0
- data/solara/lib/core/doctor/validator/json_schema_validator.rb +32 -0
- data/solara/lib/core/doctor/validator/project_filesystem_validator.rb +70 -0
- data/solara/lib/core/doctor/validator/template/android_template_validation_config.yml +51 -0
- data/solara/lib/core/doctor/validator/template/flutter_template_validation_config.yml +53 -0
- data/solara/lib/core/doctor/validator/template/ios_template_validation_config.yml +51 -0
- data/solara/lib/core/doctor/validator/template/template_validator.rb +108 -0
- data/solara/lib/core/doctor/validator/validation_strategy.rb +7 -0
- data/solara/lib/core/scripts/brand_config_generator.rb +245 -0
- data/solara/lib/core/scripts/brand_config_manager.rb +90 -0
- data/solara/lib/core/scripts/brand_exporter.rb +38 -0
- data/solara/lib/core/scripts/brand_importer.rb +84 -0
- data/solara/lib/core/scripts/brand_offboarder.rb +19 -0
- data/solara/lib/core/scripts/brand_resources_manager.rb +77 -0
- data/solara/lib/core/scripts/directory_creator.rb +22 -0
- data/solara/lib/core/scripts/file_manager.rb +90 -0
- data/solara/lib/core/scripts/file_path.rb +327 -0
- data/solara/lib/core/scripts/folder_copier.rb +41 -0
- data/solara/lib/core/scripts/gitignore_manager.rb +54 -0
- data/solara/lib/core/scripts/interactive_file_system_validator.rb +110 -0
- data/solara/lib/core/scripts/platform/android/android_manifest_switcher.rb +24 -0
- data/solara/lib/core/scripts/platform/android/android_strings_switcher.rb +39 -0
- data/solara/lib/core/scripts/platform/android/gradle_switcher.rb +233 -0
- data/solara/lib/core/scripts/platform/android/properties_generator.rb +31 -0
- data/solara/lib/core/scripts/platform/ios/ios_file_path_manager.rb +109 -0
- data/solara/lib/core/scripts/platform/ios/ios_plist_manager.rb +42 -0
- data/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +44 -0
- data/solara/lib/core/scripts/platform/ios/xcode_asset_manager.rb +56 -0
- data/solara/lib/core/scripts/platform/ios/xcode_project_manager.rb +82 -0
- data/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +130 -0
- data/solara/lib/core/scripts/project_settings_manager.rb +39 -0
- data/solara/lib/core/scripts/solara_logger.rb +103 -0
- data/solara/lib/core/scripts/solara_settings_manager.rb +73 -0
- data/solara/lib/core/scripts/solara_status_manager.rb +55 -0
- data/solara/lib/core/scripts/solara_version_manager.rb +42 -0
- data/solara/lib/core/scripts/strings_xml_manager.rb +22 -0
- data/solara/lib/core/scripts/terminal_input_manager.rb +22 -0
- data/solara/lib/core/scripts/theme_generator.rb +250 -0
- data/solara/lib/core/scripts/yaml_manager.rb +72 -0
- data/solara/lib/core/solara_configurator.rb +15 -0
- data/solara/lib/core/template/brands/android/android_config.json +8 -0
- data/solara/lib/core/template/brands/android/android_signing.json +6 -0
- data/solara/lib/core/template/brands/android/res/.DS_Store +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- data/solara/lib/core/template/brands/android/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- data/solara/lib/core/template/brands/brands.json +4 -0
- data/solara/lib/core/template/brands/ios/assets/.DS_Store +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/100.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/102.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/1024.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/114.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/120.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/128.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/144.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/152.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/16.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/167.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/172.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/180.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/196.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/20.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/216.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/256.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/29.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/32.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/40.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/48.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/50.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/512.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/55.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/57.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/58.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/60.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/64.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/66.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/72.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/76.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/80.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/87.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/88.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/92.png +0 -0
- data/solara/lib/core/template/brands/ios/assets/AppIcon.appiconset/Contents.json +1 -0
- data/solara/lib/core/template/brands/ios/ios_config.json +7 -0
- data/solara/lib/core/template/brands/ios/ios_signing.json +7 -0
- data/solara/lib/core/template/brands/shared/.DS_Store +0 -0
- data/solara/lib/core/template/brands/shared/brand_config.json +2 -0
- data/solara/lib/core/template/brands/shared/theme.json +46 -0
- data/solara/lib/core/template/config/android_template_config.json +57 -0
- data/solara/lib/core/template/config/flutter_template_config.json +62 -0
- data/solara/lib/core/template/config/ios_template_config.json +57 -0
- data/solara/lib/core/template/project_template_generator.rb +63 -0
- data/solara/lib/platform_detector.rb +84 -0
- data/solara/lib/solara/cli.rb +5 -0
- data/solara/lib/solara/version.rb +3 -0
- data/solara/lib/solara.rb +238 -0
- data/solara/lib/solara_initializer.rb +44 -0
- data/solara/lib/solara_manager.rb +73 -0
- metadata +346 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import Ajv from 'https://cdn.skypack.dev/ajv@8.11.0';
|
|
2
|
+
|
|
3
|
+
class BrandRemoteSource {
|
|
4
|
+
constructor() {
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
async fetchBrandDetails(brandKey) {
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async fetchCurrentBrand(brandKey) {
|
|
12
|
+
// Empty for now
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async saveSection(sectionItem, configuration, brandKey) {
|
|
16
|
+
// Empty for now
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async switchToBrand(brandKey) {
|
|
20
|
+
// Empty for now
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async checkBrandHealth(brandKey) {
|
|
24
|
+
// Empty for now
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async createNewBrandConfogurations() {
|
|
28
|
+
const configurations_template = `
|
|
29
|
+
[
|
|
30
|
+
{
|
|
31
|
+
"key": "theme",
|
|
32
|
+
"name": "Theme Configuration",
|
|
33
|
+
"inputType": "color",
|
|
34
|
+
"content": {
|
|
35
|
+
"colors": {
|
|
36
|
+
"primary": "#CAAC16",
|
|
37
|
+
"secondary": "#5AC8FA",
|
|
38
|
+
"background": "#FFFFFF",
|
|
39
|
+
"surface": "#F2F2F7",
|
|
40
|
+
"error": "#FF3B30",
|
|
41
|
+
"onPrimary": "#FFFFFF",
|
|
42
|
+
"onSecondary": "#000000",
|
|
43
|
+
"onBackground": "#000000",
|
|
44
|
+
"onSurface": "#000000",
|
|
45
|
+
"onError": "#FFFFFF"
|
|
46
|
+
},
|
|
47
|
+
"typography": {
|
|
48
|
+
"fontFamily": {
|
|
49
|
+
"regular": "Roboto",
|
|
50
|
+
"medium": "Roboto-Medium",
|
|
51
|
+
"bold": "Roboto-Bold"
|
|
52
|
+
},
|
|
53
|
+
"fontSize": {
|
|
54
|
+
"small": 12,
|
|
55
|
+
"medium": 16,
|
|
56
|
+
"large": 20,
|
|
57
|
+
"extraLarge": 24
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"spacing": {
|
|
61
|
+
"small": 8,
|
|
62
|
+
"medium": 16,
|
|
63
|
+
"large": 24,
|
|
64
|
+
"extraLarge": 32
|
|
65
|
+
},
|
|
66
|
+
"borderRadius": {
|
|
67
|
+
"small": 4,
|
|
68
|
+
"medium": 8,
|
|
69
|
+
"large": 12
|
|
70
|
+
},
|
|
71
|
+
"elevation": {
|
|
72
|
+
"none": 0,
|
|
73
|
+
"low": 2,
|
|
74
|
+
"medium": 4,
|
|
75
|
+
"high": 8
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"key": "brand_config",
|
|
81
|
+
"name": "Brand Configuration",
|
|
82
|
+
"inputType": "text",
|
|
83
|
+
"content": {}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"key": "android_config",
|
|
87
|
+
"name": "Android Platform Configuration",
|
|
88
|
+
"inputType": "text",
|
|
89
|
+
"content": {
|
|
90
|
+
"brandName": "",
|
|
91
|
+
"applicationId": "",
|
|
92
|
+
"versionName": "1.0.0",
|
|
93
|
+
"versionCode": 1,
|
|
94
|
+
"sourceSets": []
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"key": "android_signing",
|
|
99
|
+
"name": "Android Signing",
|
|
100
|
+
"inputType": "text",
|
|
101
|
+
"content": {
|
|
102
|
+
"storeFile": "",
|
|
103
|
+
"keyAlias": "",
|
|
104
|
+
"storePassword": "",
|
|
105
|
+
"keyPassword": ""
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"key": "ios_config",
|
|
110
|
+
"name": "iOS Platform Configuration",
|
|
111
|
+
"inputType": "text",
|
|
112
|
+
"content": {
|
|
113
|
+
"PRODUCT_NAME": "",
|
|
114
|
+
"PRODUCT_BUNDLE_IDENTIFIER": "",
|
|
115
|
+
"MARKETING_VERSION": "1.0.0",
|
|
116
|
+
"BUNDLE_VERSION": "1",
|
|
117
|
+
"APL_MRCH_ID": ""
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"key": "ios_signing",
|
|
122
|
+
"name": "iOS Signing",
|
|
123
|
+
"inputType": "text",
|
|
124
|
+
"content": {
|
|
125
|
+
"CODE_SIGN_IDENTITY": "",
|
|
126
|
+
"DEVELOPMENT_TEAM": "",
|
|
127
|
+
"PROVISIONING_PROFILE_SPECIFIER": "",
|
|
128
|
+
"CODE_SIGN_STYLE": "Automatic",
|
|
129
|
+
"CODE_SIGN_ENTITLEMENTS": ""
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
]`;
|
|
133
|
+
return JSON.parse(configurations_template);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async getBrandConfigurationsJsonFromDirectory(dirHandle) {
|
|
137
|
+
const schema = await this.fetchBrandConfigurationsSchema();
|
|
138
|
+
|
|
139
|
+
const ajv = new Ajv();
|
|
140
|
+
const validate = ajv.compile(schema);
|
|
141
|
+
|
|
142
|
+
const text = await dirHandle.text();
|
|
143
|
+
let json;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
json = JSON.parse(text);
|
|
147
|
+
} catch (e) {
|
|
148
|
+
console.error("Invalid JSON:", e);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const valid = validate(json);
|
|
153
|
+
|
|
154
|
+
if (valid) {
|
|
155
|
+
return json;
|
|
156
|
+
} else {
|
|
157
|
+
console.error("Schema validation failed:", validate.errors);
|
|
158
|
+
const errorMessages = validate.errors.map(error => `${error.instancePath}: ${error.message}`).join(', ');
|
|
159
|
+
alert(`The selected JSON file is not a valid configuration for Solara brands. Errors: ${errorMessages}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async fetchBrandConfigurationsSchema() {
|
|
166
|
+
const url = "https://raw.githubusercontent.com/Solara-Kit/Solara/main/solara/lib/core/doctor/schema/brand_configurations.json";
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
const response = await fetch(url);
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
throw new Error('Network response was not ok: ' + response.statusText);
|
|
172
|
+
}
|
|
173
|
+
const data = await response.json();
|
|
174
|
+
console.log(data);
|
|
175
|
+
return data; // Return the data instead of null
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('There was a problem with the fetch operation:', error);
|
|
178
|
+
return null; // Return null in case of error
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async createBrandConfigurationsFromDirectory(dirHandle) {
|
|
183
|
+
const configList = [];
|
|
184
|
+
const expectedFiles = [
|
|
185
|
+
{
|
|
186
|
+
key: 'theme',
|
|
187
|
+
name: 'Theme Configuration',
|
|
188
|
+
input_type: 'color',
|
|
189
|
+
filename: 'theme.json'
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
key: 'brand_config',
|
|
193
|
+
name: 'Brand Configuration',
|
|
194
|
+
input_type: 'text',
|
|
195
|
+
filename: 'brand_config.json'
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: 'android_config',
|
|
199
|
+
name: 'Android Platform Configuration',
|
|
200
|
+
input_type: 'text',
|
|
201
|
+
filename: 'android_config.json'
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
key: 'android_signing',
|
|
205
|
+
name: 'Android Signing',
|
|
206
|
+
input_type: 'text',
|
|
207
|
+
filename: 'android_signing.json'
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
key: 'ios_config',
|
|
211
|
+
name: 'iOS Platform Configuration',
|
|
212
|
+
input_type: 'text',
|
|
213
|
+
filename: 'ios_config.json'
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: 'ios_signing',
|
|
217
|
+
name: 'iOS Signing',
|
|
218
|
+
input_type: 'text',
|
|
219
|
+
filename: 'ios_signing.json'
|
|
220
|
+
}
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
for (const file of expectedFiles) {
|
|
224
|
+
try {
|
|
225
|
+
const fileContent = await this.findAndReadFile(dirHandle, file.filename);
|
|
226
|
+
if (fileContent) {
|
|
227
|
+
configList.push({
|
|
228
|
+
key: file.key,
|
|
229
|
+
name: file.name,
|
|
230
|
+
inputType: file.input_type,
|
|
231
|
+
content: JSON.parse(fileContent)
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.warn(`File not found or invalid JSON: ${file.filename}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return configList;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async findAndReadFile(dirHandle, filename) {
|
|
243
|
+
const queue = [dirHandle];
|
|
244
|
+
while (queue.length > 0) {
|
|
245
|
+
const currentHandle = queue.shift();
|
|
246
|
+
for await (const entry of currentHandle.values()) {
|
|
247
|
+
if (entry.kind === 'file' && entry.name === filename) {
|
|
248
|
+
const file = await entry.getFile();
|
|
249
|
+
return await file.text();
|
|
250
|
+
} else if (entry.kind === 'directory') {
|
|
251
|
+
queue.push(entry);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export default BrandRemoteSource;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import BrandsModel from './BrandsModel.js';
|
|
2
|
+
import BrandsView from './BrandsView.js';
|
|
3
|
+
import BrandsController from './BrandsController.js';
|
|
4
|
+
|
|
5
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
6
|
+
const model = new BrandsModel();
|
|
7
|
+
const view = new BrandsView(model.source);
|
|
8
|
+
const controller = new BrandsController(model, view);
|
|
9
|
+
await controller.init();
|
|
10
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
class BrandsController {
|
|
2
|
+
constructor(model, view) {
|
|
3
|
+
this.model = model;
|
|
4
|
+
this.view = view;
|
|
5
|
+
this.view.setOnSwitch(this.switchToBrand.bind(this));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async init() {
|
|
9
|
+
await this.model.fetchCurrentBrand();
|
|
10
|
+
await this.renderBrands();
|
|
11
|
+
await this.checkBrandsHealth();
|
|
12
|
+
this.attachEventListeners();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async renderBrands() {
|
|
16
|
+
const brands = await this.model.fetchBrands();
|
|
17
|
+
this.view.renderBrands(brands, this.model.currentBrand);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
attachEventListeners() {
|
|
21
|
+
document.querySelector('.onboard-brand-button')
|
|
22
|
+
.addEventListener('click', () => this.showOnboardBrandForm());
|
|
23
|
+
document.getElementById('brandSearch')
|
|
24
|
+
.addEventListener('input', (e) => this.filterBrands(e.target.value));
|
|
25
|
+
|
|
26
|
+
this.view.brandOptionsSheet.addEventListener('clone', (event) => {
|
|
27
|
+
console.log('Clone', event.detail);
|
|
28
|
+
this.handleCloneOption(event)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.view.brandOptionsSheet.addEventListener('offboard', (event) => {
|
|
32
|
+
console.log('Offboard', event.detail);
|
|
33
|
+
this.handleOffboardOption(event)
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
this.view.brandOptionsSheet.addEventListener('doctor', (event) => {
|
|
37
|
+
console.log('Doctor', event.detail);
|
|
38
|
+
this.handleDoctorOption(event)
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
this.view.brandOptionsSheet.addEventListener('aliases', (event) => {
|
|
42
|
+
console.log('Aliases', event.detail);
|
|
43
|
+
this.handleAliasesOption(event)
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.view.brandOptionsSheet.addEventListener('settings', (event) => {
|
|
47
|
+
console.log('Settings', event.detail);
|
|
48
|
+
this.handleSettingsOption(event)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
showOnboardBrandForm() {
|
|
53
|
+
this.view.showOnboardBrandForm();
|
|
54
|
+
this.view.onboardSheet.addEventListener('onboard', async (event) => {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
const {brandKey, brandName} = event.detail;
|
|
57
|
+
await this.handleOnboardBrandSubmit(brandKey, brandName);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async handleOnboardBrandSubmit(brandKey, brandName) {
|
|
62
|
+
try {
|
|
63
|
+
await this.model.onboardBrand(brandName, brandKey);
|
|
64
|
+
await this.view.hideOnboardBrandForm();
|
|
65
|
+
location.reload();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Error during submission:', error);
|
|
68
|
+
alert(error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
filterBrands(searchTerm) {
|
|
73
|
+
const filteredBrands = this.model.filterBrands(searchTerm);
|
|
74
|
+
this.view.renderBrands(filteredBrands, this.model.currentBrand);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async checkBrandsHealth() {
|
|
78
|
+
const result = await this.model.runDoctor("");
|
|
79
|
+
const errorButton = document.getElementById('error-button');
|
|
80
|
+
|
|
81
|
+
if (!result.passed) {
|
|
82
|
+
this.view.showErrorButton();
|
|
83
|
+
this.view.updateErrorCount(result.errors.length);
|
|
84
|
+
|
|
85
|
+
errorButton.addEventListener('click', () => {
|
|
86
|
+
const errors = result.errors
|
|
87
|
+
.map((error, index) => `${index + 1}. ${error}`)
|
|
88
|
+
.join('\n');
|
|
89
|
+
this.view.showMessage(`Health check for all brands completed with errors: \n\n${errors}`);
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
this.view.hideErrorButton();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
handleCloneOption(event) {
|
|
97
|
+
event.stopPropagation();
|
|
98
|
+
this.showOnboardBrandForm();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
handleOffboardOption(event) {
|
|
102
|
+
event.stopPropagation();
|
|
103
|
+
const brandKey = this.view.brandOptionsSheet.dataset.brandKey;
|
|
104
|
+
const brandName = this.view.brandOptionsSheet.dataset.brandName;
|
|
105
|
+
this.view.showConfirmationDialog(`Are you sure you need to offboard ${brandKey} (${brandName}) and delete all its configurations?`,
|
|
106
|
+
async () => {
|
|
107
|
+
await this.model.offboardBrand(brandKey);
|
|
108
|
+
location.reload();
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async handleDoctorOption(event) {
|
|
113
|
+
event.stopPropagation();
|
|
114
|
+
|
|
115
|
+
const brandKey = this.view.brandOptionsSheet.dataset.brandKey;
|
|
116
|
+
const result = await this.model.runDoctor(brandKey);
|
|
117
|
+
if (!result.passed) {
|
|
118
|
+
const errors = result.errors
|
|
119
|
+
.map((error, index) => `${index + 1}. ${error}`)
|
|
120
|
+
.join('\n');
|
|
121
|
+
this.view.showMessage(`Health check for ${brandKey} completed with errors:\n${errors}`);
|
|
122
|
+
} else {
|
|
123
|
+
this.view.showMessage(`Health check for ${brandKey}. All systems operational.`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async handleAliasesOption(event) {
|
|
128
|
+
event.stopPropagation();
|
|
129
|
+
|
|
130
|
+
const brandKey = this.view.brandOptionsSheet.dataset.brandKey;
|
|
131
|
+
const aliases = await this.model.fetchAliases(brandKey);
|
|
132
|
+
if (aliases) {
|
|
133
|
+
this.view.showAliasesBottomSheet(aliases, brandKey);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
handleSettingsOption(event) {
|
|
138
|
+
event.stopPropagation();
|
|
139
|
+
|
|
140
|
+
const brandKey = this.view.brandOptionsSheet.dataset.brandKey;
|
|
141
|
+
window.location.href = this.view.brandUrl(brandKey);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async switchToBrand(brandKey) {
|
|
145
|
+
try {
|
|
146
|
+
await this.model.switchToBrand(brandKey);
|
|
147
|
+
location.reload();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('Error switching to brand:', error);
|
|
150
|
+
alert(error.message);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default BrandsController;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
class BrandsModel {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.allBrands = [];
|
|
4
|
+
this.currentBrand = null;
|
|
5
|
+
this.source = this.getQueryFromUrl('source') || 'remote';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
getQueryFromUrl(name) {
|
|
9
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
10
|
+
return urlParams.get(name);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async fetchCurrentBrand() {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch('/brand/current');
|
|
16
|
+
let result = await response.json();
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
throw new Error(result.error);
|
|
19
|
+
}
|
|
20
|
+
this.currentBrand = result;
|
|
21
|
+
return result;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Error fetching current brand:', error);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async fetchBrands() {
|
|
29
|
+
try {
|
|
30
|
+
const response = await fetch('/brands.json');
|
|
31
|
+
const result = await response.json();
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
throw new Error(result.error);
|
|
34
|
+
}
|
|
35
|
+
this.allBrands = result.sort((a, b) => a.key.localeCompare(b.key));
|
|
36
|
+
return this.allBrands;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Error fetching brands:', error);
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async fetchAliases(brand) {
|
|
44
|
+
try {
|
|
45
|
+
const response = await fetch(`/brand/aliases?brand_key=${brand.key}`);
|
|
46
|
+
let result = await response.json();
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
throw new Error(result.error);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Error fetching aliases:', error);
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async switchToBrand(brandKey) {
|
|
58
|
+
try {
|
|
59
|
+
const response = await fetch('/switch', {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': 'application/json',
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify({brand_key: brandKey}),
|
|
65
|
+
});
|
|
66
|
+
const result = await response.json();
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
throw new Error(result.error);
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('Error switching to brand:', error);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async onboardBrand(brandName, brandKey, cloneBrandKey = null) {
|
|
78
|
+
try {
|
|
79
|
+
const response = await fetch('/brand/onboard', {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
headers: {
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
},
|
|
84
|
+
body: JSON.stringify({brand_name: brandName, brand_key: brandKey, clone_brand_key: cloneBrandKey}),
|
|
85
|
+
});
|
|
86
|
+
const result = await response.json();
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
throw new Error(result.error);
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error('Error onboarding brand:', error);
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async offboardBrand(brandKey) {
|
|
98
|
+
try {
|
|
99
|
+
const response = await fetch(`/brand/offboard?brand_key=${encodeURIComponent(brandKey)}`, {
|
|
100
|
+
method: 'GET',
|
|
101
|
+
});
|
|
102
|
+
const result = await response.json();
|
|
103
|
+
if (!response.ok) {
|
|
104
|
+
throw new Error(result.error);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error('Error offboarding brand:', error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async runDoctor(brandKey) {
|
|
114
|
+
try {
|
|
115
|
+
const response = await fetch(`/brand/doctor?brand_key=${encodeURIComponent(brandKey)}`);
|
|
116
|
+
const result = await response.json();
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new Error(result.error);
|
|
119
|
+
}
|
|
120
|
+
return result.result;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Error calling doctor API:', error);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
filterBrands(searchTerm) {
|
|
128
|
+
return this.allBrands.filter(brand =>
|
|
129
|
+
brand.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
130
|
+
brand.key.toLowerCase().includes(searchTerm.toLowerCase())
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default BrandsModel;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import '../component/OnboardBrandBottomSheet.js';
|
|
2
|
+
import '../component/ConfirmationDialog.js';
|
|
3
|
+
import '../component/MessageBottomSheet.js';
|
|
4
|
+
import '../component/BrandOptionsBottomSheet.js';
|
|
5
|
+
import '../component/AliasesBottomSheet.js';
|
|
6
|
+
|
|
7
|
+
class BrandsView {
|
|
8
|
+
constructor(source) {
|
|
9
|
+
this.source = source
|
|
10
|
+
this.brandList = document.getElementById('brandList');
|
|
11
|
+
this.currentBrandSection = document.getElementById('currentBrandSection');
|
|
12
|
+
this.currentBrandItem = document.getElementById('currentBrandItem');
|
|
13
|
+
this.brandOptionsSheet = document.getElementById('bottomSheet');
|
|
14
|
+
this.confirmationDialog = document.getElementById('confirmationDialog');
|
|
15
|
+
this.messageBottomSheet = document.getElementById('messageBottomSheet');
|
|
16
|
+
this.onboardSheet = document.getElementById('onboardBottomSheet');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
createBrandItem(brand, isCurrent = false) {
|
|
20
|
+
const brandItem = document.createElement('div');
|
|
21
|
+
brandItem.className = 'brand-item';
|
|
22
|
+
brandItem.innerHTML = `
|
|
23
|
+
<div class="brand-image">
|
|
24
|
+
<img src="../brand/icon?brand_key=${brand.key}" alt="${brand.name} icon">
|
|
25
|
+
</div>
|
|
26
|
+
<div class="brand-info">
|
|
27
|
+
<div class="brand-name">${brand.name}</div>
|
|
28
|
+
<div class="brand-key">${brand.key}</div>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="brand-actions">
|
|
31
|
+
<button class="switch-button">Switch</button>
|
|
32
|
+
<div class="overflow-menu">
|
|
33
|
+
<i class="fas fa-ellipsis-v"></i>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
brandItem.addEventListener('click', () => {
|
|
39
|
+
window.location.href = this.brandUrl(brand.key);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const switchButton = brandItem.querySelector('.switch-button');
|
|
43
|
+
if (isCurrent && brand.content_changed) {
|
|
44
|
+
switchButton.textContent = "Apply Changes";
|
|
45
|
+
switchButton.style.display = "block";
|
|
46
|
+
} else if (isCurrent && !brand.content_changed) {
|
|
47
|
+
switchButton.style.display = "none";
|
|
48
|
+
} else {
|
|
49
|
+
switchButton.style.display = "block";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
switchButton.addEventListener('click', async (event) => {
|
|
53
|
+
event.stopPropagation(); // Prevent the click from bubbling up to the parent
|
|
54
|
+
await this.onSwitch(brand.key);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Add click event for the overflow menu
|
|
58
|
+
const overflowMenu = brandItem.querySelector('.overflow-menu');
|
|
59
|
+
overflowMenu.addEventListener('click', (event) => {
|
|
60
|
+
event.stopPropagation();
|
|
61
|
+
this.showBrandOptionsSheet(brand);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
brandItem.dataset.brand = brand.key;
|
|
65
|
+
return brandItem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
renderBrands(brands, currentBrand) {
|
|
69
|
+
this.brandList.innerHTML = '';
|
|
70
|
+
this.currentBrandItem.innerHTML = '';
|
|
71
|
+
|
|
72
|
+
if (currentBrand) {
|
|
73
|
+
this.currentBrandSection.style.display = 'block';
|
|
74
|
+
this.currentBrandItem.appendChild(this.createBrandItem(currentBrand, true));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
brands.forEach(brand => {
|
|
78
|
+
if (!currentBrand || brand.key !== currentBrand.key) {
|
|
79
|
+
const brandItem = this.createBrandItem(brand);
|
|
80
|
+
this.brandList.appendChild(brandItem);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
showOnboardBrandForm() {
|
|
86
|
+
this.onboardSheet.show();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async hideOnboardBrandForm() {
|
|
90
|
+
this.onboardSheet.hide();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
showAliasesBottomSheet(aliases, brand) {
|
|
94
|
+
const aliasesSheet = document.getElementById('aliasesSheet');
|
|
95
|
+
aliasesSheet.show(aliases, brand);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
showBrandOptionsSheet(brand) {
|
|
99
|
+
this.brandOptionsSheet.dataset.brandName = brand.name;
|
|
100
|
+
this.brandOptionsSheet.dataset.brandKey = brand.key;
|
|
101
|
+
this.brandOptionsSheet.show();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
showConfirmationDialog(message, onConfirm) {
|
|
105
|
+
this.confirmationDialog.showDialog(message, onConfirm);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
showMessage(message) {
|
|
109
|
+
this.messageBottomSheet.showMessage(message);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
updateErrorCount(count) {
|
|
113
|
+
const countElement = document.querySelector('.count');
|
|
114
|
+
countElement.textContent = count;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
showErrorButton() {
|
|
118
|
+
const errorButton = document.getElementById('error-button');
|
|
119
|
+
errorButton.style.display = "flex";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
hideErrorButton() {
|
|
123
|
+
const errorButton = document.getElementById('error-button');
|
|
124
|
+
errorButton.style.display = "none";
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
setOnSwitch(handler) {
|
|
128
|
+
this.onSwitch = handler;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
brandUrl(brandKey) {
|
|
132
|
+
return `../brand/brand.html?brand_key=${encodeURIComponent(brandKey)}&source=${this.source}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export default BrandsView;
|