@simitgroup/simpleapp-generator 1.6.7-h-alpha → 1.6.7-i-alpha

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 (35) hide show
  1. package/ReleaseNote.md +6 -0
  2. package/dist/generate.js +2 -0
  3. package/dist/generate.js.map +1 -1
  4. package/package.json +1 -1
  5. package/src/generate.ts +2 -0
  6. package/templates/basic/miniApi/resource.controller.ts.eta +10 -3
  7. package/templates/basic/miniApi/resource.service.ts.eta +9 -2
  8. package/templates/basic/nest/apischema.ts.eta +21 -6
  9. package/templates/basic/nest/controller.ts.eta +37 -16
  10. package/templates/basic/nuxt/resource-bridge.service.ts.eta +3 -2
  11. package/templates/miniApi/src/constants/api-scopes.ts.eta +1 -1
  12. package/templates/nest/src/simpleapp/generate/commons/middlewares/tenant.middleware.ts.eta +34 -14
  13. package/templates/nest/src/simpleapp/generate/commons/robotuser.service.ts.eta +4 -8
  14. package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +154 -17
  15. package/templates/nuxt/composables/getUserStore.generate.ts.eta +62 -66
  16. package/templates/nuxt/plugins/19.simpleapp-mini-app-store.ts.eta +240 -203
  17. package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +1 -1
  18. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppFeatureCustomField.vue.eta +34 -0
  19. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppFeatureCustomPage.vue.eta +68 -0
  20. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppFeatureScope.vue.eta +53 -0
  21. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppIcon.vue.eta +49 -0
  22. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppMenuButton.vue.eta +6 -4
  23. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppPageIframe.vue.eta +9 -3
  24. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppPermissionWrapper.vue.eta +4 -4
  25. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppRestrictedWarning.vue.eta +3 -3
  26. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppSettingLayout.vue.eta +3 -3
  27. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppSettingPage.vue.eta +2 -2
  28. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/MiniAppWrapper.vue.eta +2 -32
  29. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationItem.vue.eta +6 -5
  30. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationItemBadge.vue.eta +15 -9
  31. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationItemGroup.vue.eta +4 -4
  32. package/templates/nuxt/simpleapp/generate/features/miniApp/app/components/integration/MiniAppIntegrationPage.vue.eta +135 -22
  33. package/templates/nuxt/simpleapp/generate/features/miniApp/app/types/miniApp.ts.eta +7 -7
  34. package/templates/nuxt/simpleapp/generate/features/miniApp/bridge/services/bridge-resource-accessor.service.ts.eta +3 -1
  35. package/templates/nuxt/simpleapp/generate/features/miniApp/bridge/services/bridge.service.ts.eta +3 -0
@@ -8,15 +8,12 @@ import _, { min } from "lodash";
8
8
  import {
9
9
  Miniapp,
10
10
  MiniAppDetail,
11
- MiniAppDetailActionAccess,
12
- MiniappIntegrationPages,
11
+ MiniAppDetailPermission,
12
+ MiniappIntegrationCustomPagePages,
13
13
  MINIAPPMANAGERApi,
14
14
  } from "~/simpleapp/generate/openapi";
15
- import {
16
- MiniAppFormWithMiniAppCode,
17
- MiniAppFrameworkCompatibility,
18
- MiniAppPermissionResult,
19
- } from "~/simpleapp/generate/features/miniApp/app/types/miniApp";
15
+ import { MiniAppFormWithMiniAppCode } from "~/simpleapp/generate/features/miniApp/app/types/miniApp";
16
+ import { MiniappEnvEnum } from "~/enums/enums.generate";
20
17
 
21
18
  export default defineNuxtPlugin(async () => {
22
19
  /**
@@ -24,38 +21,15 @@ export default defineNuxtPlugin(async () => {
24
21
  */
25
22
  const MINI_APP_PAGE_PATH_PREFIX = "miniapp";
26
23
 
27
- /**
28
- * To totally block mini app. if mini app's framework compability lower than this.
29
- * To support backward compatibility, with deprecation notice,
30
- * if mini app's framework compability higher than this, but lower than MIN_FRAMEWORK_COMPATIBLE_VERSION.
31
- */
32
- const MIN_FRAMEWORK_VERSION = "1.0";
33
-
34
- /**
35
- * The minimum version that is compatible with the current framework.
36
- */
37
- const MIN_FRAMEWORK_COMPATIBLE_VERSION = "1.0";
38
-
39
24
  const config = getAxiosConfig();
40
25
 
41
26
  const miniAppManager = new MINIAPPMANAGERApi(config);
42
27
 
43
28
  const MINI_APP_BUILT_IN_SETTING_NAME = "mini-app-setting";
44
29
 
45
- const _ERROR = {
46
- MISSING_REQUIRED_PLAN: "missingRequiredPlan",
47
- INSUFFICIENT_ACCESS_PERMISSION: "insufficientAccessPermission",
48
- INSUFFICIENT_INSTALL_PERMISSION: "insufficientInstallPermission",
49
- INSUFFICIENT_UNINSTALL_PERMISSION: "insufficientUninstallPermission",
50
- INSUFFICIENT_CHANGE_SETTING_PERMISSION:
51
- "insufficientChangeSettingPermission",
52
- NO_MINI_APP_FEATURE: "packageTypeRestricted",
53
- NOT_YET_INSTALL: "notYetInstall",
54
- };
55
-
56
30
  const useMiniAppStore = defineStore("mini-app", {
57
31
  state: () => ({
58
- actionAccess: {} as MiniAppDetailActionAccess,
32
+ permissions: {} as MiniAppDetailPermission,
59
33
 
60
34
  /**
61
35
  * Store all installed miniApps
@@ -67,10 +41,15 @@ export default defineNuxtPlugin(async () => {
67
41
  */
68
42
  isFetchingInstalledMiniApps: true,
69
43
  }),
44
+
70
45
  getters: {
71
46
  getForm: (state) => (formCode: string) => {
47
+ if (!state.permissions.hasMiniAppFeature) {
48
+ return [];
49
+ }
50
+
72
51
  return state.installedMiniApps.flatMap((miniApp) => {
73
- return miniApp.integration.forms
52
+ return (miniApp.integration?.customField?.fields ?? [])
74
53
  .filter((form) => form.code == formCode)
75
54
  .map((form) => {
76
55
  return {
@@ -81,64 +60,250 @@ export default defineNuxtPlugin(async () => {
81
60
  });
82
61
  },
83
62
 
84
- isHaveMiniAppFeature: (state) => {
85
- if (state.isFetchingInstalledMiniApps) {
86
- // if still fetching, return true 1st, else will immediate show restricted warning
87
- return true;
63
+ showMiniAppMoreMenuButton: (state) => {
64
+ if (!state.permissions.hasMiniAppFeature) {
65
+ return false;
88
66
  }
89
67
 
90
- return state.actionAccess.isHaveMiniAppFeature ?? false;
91
- },
92
-
93
- isShowMiniAppMoreMenuButton: (state) => {
94
68
  const filtered = state.installedMiniApps.filter(
95
69
  (item) =>
96
- item.integration?.pages?.length > 0 ||
97
- (item.integration?.settings?.jsonSchema &&
98
- Object.keys(item.integration.settings.jsonSchema).length > 0),
70
+ item.integration?.customPage?.pages &&
71
+ (item.integration?.customPage?.pages?.length > 0 ||
72
+ (item.integration?.customPage?.setting?.jsonSchema &&
73
+ Object.keys(item.integration.customPage.setting.jsonSchema)
74
+ .length > 0)),
99
75
  );
100
76
 
101
77
  return _.isEmpty(filtered) ? false : true;
102
78
  },
103
79
 
104
- isCanInstall: (state) => state.actionAccess.isAllowInstall,
105
- isCanUninstall: (state) => state.actionAccess.isAllowUninstall,
106
- isCanUpdateSetting: (state) => state.actionAccess.isAllowUpdateSetting,
107
- isHasMiniAppFeature: (state) => state.actionAccess.isHaveMiniAppFeature,
80
+ // ================================= Permission =================================
81
+ canInstall: (state) => state.permissions.canInstall,
82
+ canUninstall: (state) => state.permissions.canUninstall,
83
+ canUpdateSetting: (state) => state.permissions.canUpdateSetting,
84
+ hasMiniAppFeature: (state) => state.permissions.hasMiniAppFeature,
108
85
  },
109
86
 
110
87
  actions: {
111
- getMenuItems() {
112
- return this.installedMiniApps.flatMap((miniApp) => {
113
- const pages = miniApp.integration.pages.filter((page) => {
88
+ // ================================= Finder =================================
89
+ findMiniApp(miniApps: MiniAppDetail[], miniAppCode: string) {
90
+ return miniApps.find((item) => item.code === miniAppCode);
91
+ },
92
+
93
+ findPage(miniApp: MiniAppDetail, pageCode: string) {
94
+ if (pageCode === MINI_APP_BUILT_IN_SETTING_NAME) {
95
+ return this.getSettingPageMenu(miniApp);
96
+ }
97
+
98
+ return miniApp.integration?.customPage?.pages.find(
99
+ (item) => item.code === pageCode,
100
+ );
101
+ },
102
+
103
+ // ================================= Permission =================================
104
+ hasPermission(requiredPermissions: string[], env: MiniappEnvEnum) {
105
+ if (env === MiniappEnvEnum.DEV) {
106
+ return true;
107
+ }
108
+
109
+ if (_.isEmpty(requiredPermissions)) {
110
+ return true;
111
+ }
112
+
113
+ const userRoles = getUserProfile().roles ?? [];
114
+ return requiredPermissions.some((permission) =>
115
+ userRoles.includes(permission),
116
+ );
117
+ },
118
+
119
+ validatePageAccess(miniAppCode: string, pageCode: string) {
120
+ const miniApp = this.findMiniApp(this.installedMiniApps, miniAppCode);
121
+ if (!miniApp) {
122
+ return {
123
+ valid: false,
124
+ type: "unknownMiniApp",
125
+ };
126
+ }
127
+
128
+ const page = this.findPage(miniApp, pageCode);
129
+ if (!page) {
130
+ return {
131
+ valid: false,
132
+ type: "unknownPage",
133
+ };
134
+ }
135
+
136
+ if (!this.hasMiniAppFeature) {
137
+ return {
138
+ valid: false,
139
+ type: "miniAppFeature",
140
+ };
141
+ }
142
+
143
+ if (hasHighPrivilege()) {
144
+ return {
145
+ valid: true,
146
+ type: "highPrivilege",
147
+ };
148
+ }
149
+
150
+ if (!this.isInstalled(miniApp.code)) {
151
+ return {
152
+ valid: false,
153
+ type: "notInstalled",
154
+ };
155
+ }
156
+
157
+ if (!miniApp.hasRequiredPlan) {
158
+ return {
159
+ valid: false,
160
+ type: "requiredPlan",
161
+ };
162
+ }
163
+
164
+ if (
165
+ !this.hasPermission(
166
+ page.requiredPermissions ?? [],
167
+ miniApp.env as MiniappEnvEnum,
168
+ )
169
+ ) {
170
+ return {
171
+ valid: false,
172
+ type: "requiredPermission",
173
+ };
174
+ }
175
+
176
+ return {
177
+ valid: true,
178
+ type: "",
179
+ };
180
+ },
181
+
182
+ validation(type: string) {
183
+ switch (type) {
184
+ case "miniAppFeature":
185
+ return {
186
+ valid: this.hasMiniAppFeature,
187
+ type,
188
+ };
189
+
190
+ case "install":
191
+ return {
192
+ valid: this.canInstall,
193
+ type,
194
+ };
195
+
196
+ case "uninstall":
197
+ return {
198
+ valid: this.canUninstall,
199
+ type,
200
+ };
201
+
202
+ case "updateSetting":
203
+ return {
204
+ valid: this.canUpdateSetting,
205
+ type,
206
+ };
207
+ }
208
+
209
+ return {
210
+ valid: true,
211
+ type: "",
212
+ };
213
+ },
214
+
215
+ isInstalled(miniAppCode: string) {
216
+ const miniApp = this.installedMiniApps.find(
217
+ (item) => item.code === miniAppCode,
218
+ );
219
+
220
+ return miniApp?.miniAppInstallation?.isActive === true ? true : false;
221
+ },
222
+
223
+ canAccessPage(miniAppCode: string, pageCode: string): boolean {
224
+ const validation = this.validatePageAccess(miniAppCode, pageCode);
225
+
226
+ return validation.valid;
227
+ },
228
+
229
+ enabledMiniAppFeature(
230
+ miniApp: MiniAppDetail,
231
+ feature: keyof MiniAppDetail["integration"]["enabled"],
232
+ ) {
233
+ return miniApp.integration.enabled[feature];
234
+ },
235
+
236
+ // ================================= Menu =================================
237
+
238
+ hasSettingPage(miniApp: MiniAppDetail) {
239
+ const enabled = this.enabledMiniAppFeature(miniApp, "customPage");
240
+ if (!enabled) return false;
241
+
242
+ if (_.isEmpty(miniApp.integration?.customPage?.setting?.jsonSchema)) {
243
+ return false;
244
+ }
245
+
246
+ return true;
247
+ },
248
+
249
+ getSettingPageMenu(miniApp: MiniAppDetail) {
250
+ if (!this.canUpdateSetting) {
251
+ return null;
252
+ }
253
+
254
+ if (!this.enabledMiniAppFeature(miniApp, "customPage")) {
255
+ return null;
256
+ }
257
+
258
+ if (_.isEmpty(miniApp.integration?.customPage?.setting?.jsonSchema)) {
259
+ return null;
260
+ }
261
+
262
+ return {
263
+ code: MINI_APP_BUILT_IN_SETTING_NAME,
264
+ title: t("miniAppLang.setting"),
265
+ description: "",
266
+ sources: {
267
+ development: "",
268
+ production: "",
269
+ },
270
+ requiredPermissions: [],
271
+ iconType: "class",
272
+ icon: "pi pi-cog",
273
+ };
274
+ },
275
+
276
+ shouldShowPageOnMenu(page: MiniappIntegrationCustomPagePages) {
277
+ return page.isHideOnMenu === true ? false : true;
278
+ },
279
+
280
+ getPages(miniApp: MiniAppDetail, withSettingPage: boolean = true) {
281
+ if (!this.hasMiniAppFeature) {
282
+ return [];
283
+ }
284
+
285
+ const pages = (miniApp.integration?.customPage?.pages ?? []).filter(
286
+ (page) => {
114
287
  return (
115
- this.isAllowAccessMiniAppPage(miniApp.code, page.code) &&
116
- this.isRequiredToShowOnMenu(page)
288
+ this.canAccessPage(miniApp.code, page.code) &&
289
+ this.shouldShowPageOnMenu(page)
117
290
  );
118
- });
291
+ },
292
+ );
119
293
 
120
- if (this.isCanUpdateSetting) {
121
- if (
122
- miniApp.integration.settings?.jsonSchema &&
123
- !_.isEmpty(miniApp.integration.settings.jsonSchema)
124
- ) {
125
- pages.push({
126
- code: MINI_APP_BUILT_IN_SETTING_NAME,
127
- title: t("miniAppLang.setting"),
128
- description: "",
129
- sourceType: "",
130
- sources: {
131
- development: "",
132
- production: "",
133
- },
134
- requiredPermissions: [],
135
- iconType: "class",
136
- icon: "pi pi-cog",
137
- });
138
- }
294
+ if (withSettingPage) {
295
+ const settingPage = this.getSettingPageMenu(miniApp);
296
+ if (settingPage) {
297
+ pages.push(settingPage);
139
298
  }
299
+ }
300
+
301
+ return pages ?? [];
302
+ },
140
303
 
141
- // Only return mini app if pages not empty
304
+ getMenuItems() {
305
+ return this.installedMiniApps.flatMap((miniApp) => {
306
+ const pages = this.getPages(miniApp);
142
307
  if (_.isEmpty(pages)) {
143
308
  return [];
144
309
  }
@@ -153,9 +318,7 @@ export default defineNuxtPlugin(async () => {
153
318
  });
154
319
  },
155
320
 
156
- isRequiredToShowOnMenu(page: MiniappIntegrationPages) {
157
- return page.isHideOnMenu !== true;
158
- },
321
+ // ================================= Separator =================================
159
322
 
160
323
  // ============================ Load Function ============================
161
324
  async loadInstalledMiniApps() {
@@ -171,7 +334,7 @@ export default defineNuxtPlugin(async () => {
171
334
  });
172
335
 
173
336
  this.installedMiniApps = resp.installedMiniApps;
174
- this.actionAccess = resp.actionAccess;
337
+ this.permissions = resp.permissions;
175
338
 
176
339
  this.isFetchingInstalledMiniApps = false;
177
340
  },
@@ -198,85 +361,6 @@ export default defineNuxtPlugin(async () => {
198
361
  });
199
362
  },
200
363
 
201
- // ================================ Permission ===============================
202
-
203
- hasRequiredPlan(miniApp: Miniapp) {
204
- const currentPlan = getUserProfile().package ?? "";
205
- const requiredPlans = miniApp.requiredPlans ?? [];
206
- if (_.isEmpty(requiredPlans)) return true;
207
-
208
- return requiredPlans.includes(currentPlan);
209
- },
210
-
211
- checkHasFeature() {
212
- return this._check([
213
- [() => this.isHasMiniAppFeature, _ERROR.NO_MINI_APP_FEATURE],
214
- ]);
215
- },
216
-
217
- checkHasRequiredPlan(miniApp: Miniapp) {
218
- return this._check([
219
- [() => this.hasRequiredPlan(miniApp), _ERROR.MISSING_REQUIRED_PLAN],
220
- ]);
221
- },
222
-
223
- checkIsInstalled(miniAppCode: string) {
224
- return this._check([
225
- [() => this.isMiniAppInstalled(miniAppCode), _ERROR.NOT_YET_INSTALL],
226
- ]);
227
- },
228
-
229
- checkCanAccess(miniAppCode: string, pageCode: string) {
230
- if (pageCode === MINI_APP_BUILT_IN_SETTING_NAME) {
231
- return this._check([
232
- [
233
- () => this.isCanUpdateSetting,
234
- _ERROR.INSUFFICIENT_ACCESS_PERMISSION,
235
- ],
236
- ]);
237
- }
238
-
239
- return this._check([
240
- [
241
- () => this.isAllowAccessMiniAppPage(miniAppCode, pageCode),
242
- _ERROR.INSUFFICIENT_ACCESS_PERMISSION,
243
- ],
244
- ]);
245
- },
246
-
247
- checkCanInstall(miniApp: Miniapp) {
248
- return this._check([
249
- [() => this.hasRequiredPlan(miniApp), _ERROR.MISSING_REQUIRED_PLAN],
250
- [() => this.isCanInstall, _ERROR.INSUFFICIENT_INSTALL_PERMISSION],
251
- ]);
252
- },
253
-
254
- checkCanUninstall(miniApp: Miniapp) {
255
- return this._check([
256
- [() => this.isCanUninstall, _ERROR.INSUFFICIENT_UNINSTALL_PERMISSION],
257
- ]);
258
- },
259
-
260
- checkCanUpdateSetting(miniApp: Miniapp) {
261
- return this._check([
262
- [() => this.hasRequiredPlan(miniApp), _ERROR.MISSING_REQUIRED_PLAN],
263
- [
264
- () => this.isCanUpdateSetting,
265
- _ERROR.INSUFFICIENT_CHANGE_SETTING_PERMISSION,
266
- ],
267
- ]);
268
- },
269
-
270
- _check(checks: [() => boolean, string][]): MiniAppPermissionResult {
271
- for (const [checkFn, reason] of checks) {
272
- if (!checkFn()) {
273
- return { status: false, reason };
274
- }
275
- }
276
-
277
- return { status: true };
278
- },
279
-
280
364
  // ============================ Path & Navigation ============================
281
365
 
282
366
  getMiniAppSettingPath(miniAppCode: string) {
@@ -324,53 +408,6 @@ export default defineNuxtPlugin(async () => {
324
408
  return miniApp ? true : false;
325
409
  },
326
410
 
327
- isAllowAccessMiniAppPage(miniAppCode: string, pageCode: string) {
328
- const miniApp = this.installedMiniApps.find(
329
- (item) => item.code === miniAppCode,
330
- );
331
- if (!miniApp) {
332
- return false;
333
- }
334
-
335
- const page = miniApp.integration.pages.find(
336
- (item) => item.code === pageCode,
337
- );
338
- if (!page) {
339
- return false;
340
- }
341
-
342
- if (checkHasHighPrivilege()) {
343
- return true;
344
- }
345
-
346
- const userRoles = getUserProfile().roles;
347
-
348
- if (page.requiredPermissions && !_.isEmpty(page.requiredPermissions)) {
349
- return page.requiredPermissions.some((permission) =>
350
- userRoles.includes(permission),
351
- );
352
- }
353
- return true;
354
- },
355
-
356
- getPageInfo(miniApp: Miniapp, pageCode: string) {
357
- return miniApp.integration.pages.find((item) => item.code === pageCode);
358
- },
359
-
360
- checkMiniAppFrameworkCompatibility: (
361
- miniApp: Miniapp,
362
- ): MiniAppFrameworkCompatibility => {
363
- if (miniApp.frameworkCompatibility < MIN_FRAMEWORK_VERSION) {
364
- return MiniAppFrameworkCompatibility.DEPRECATED;
365
- }
366
-
367
- if (miniApp.frameworkCompatibility < MIN_FRAMEWORK_COMPATIBLE_VERSION) {
368
- return MiniAppFrameworkCompatibility.TO_BE_DEPRECATED;
369
- }
370
-
371
- return MiniAppFrameworkCompatibility.COMPATIBLE;
372
- },
373
-
374
411
  // ============================ miniApp Action ============================
375
412
 
376
413
  async installMiniApp(miniAppCode: string) {
@@ -165,7 +165,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
165
165
  }
166
166
  //().then((res:AxiosResponse)=>{ }
167
167
  },
168
- checkHasHighPrivilege() {
168
+ hasHighPrivilege() {
169
169
  return HIGH_PRIVILEGE_ROLES.some((permission) =>
170
170
  this.roles.includes(permission),
171
171
  );
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <div
3
+ v-if="miniApp.integration.enabled.customField"
4
+ class="flex flex-col gap-2"
5
+ >
6
+ <div
7
+ v-for="field in miniApp.integration.customField?.fields"
8
+ class="flex gap-2 bg-slate-100 rounded-xl px-4 py-3"
9
+ >
10
+ <div>
11
+ <div class="flex items-center gap-2 font-semibold text-surface-700">
12
+ <span
13
+ class="text-xs bg-primary-100 text-primary-500 px-4 py-1 rounded-md"
14
+ >{{ t(`${field.code}`) }}
15
+ </span>
16
+ <span>
17
+ {{ field.title }}
18
+ </span>
19
+ </div>
20
+
21
+ <div class="text-surface-400 text-sm mt-1">
22
+ {{ field.description }}
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+ <script setup lang="ts">
29
+ import { MiniAppDetail } from "~/simpleapp/generate/openapi";
30
+
31
+ const props = defineProps<{
32
+ miniApp: MiniAppDetail;
33
+ }>();
34
+ </script>
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <Tabs value="pages">
3
+ <TabList>
4
+ <Tab value="pages">
5
+ {{ t("pages") }}
6
+ </Tab>
7
+ <Tab value="scopes">
8
+ {{ t("scopes") }}
9
+ </Tab>
10
+ </TabList>
11
+ <TabPanels>
12
+ <TabPanel value="pages">
13
+ <div class="flex flex-col gap-2">
14
+ <div
15
+ v-for="page in miniApp.integration.customPage?.pages"
16
+ class="flex flex-col gap-2 bg-slate-100 rounded-xl px-4 py-3"
17
+ >
18
+ <div class="flex items-center gap-2">
19
+ <MiniAppPageIcon
20
+ :iconType="page.iconType"
21
+ :icon="page.icon ?? ''"
22
+ class=""
23
+ />
24
+
25
+ <div class="font-semibold text-surface-700">
26
+ {{ page.title }}
27
+ </div>
28
+ </div>
29
+ <div class="flex flex-col pl-6">
30
+ <div class="text-surface-400 text-sm mt-1">
31
+ {{ page.description }}
32
+ </div>
33
+
34
+ <template v-if="!_.isEmpty(page.requiredPermissions)">
35
+ <Divider type="dashed" class="!my-3" />
36
+
37
+ <div class="flex items-center gap-2 flex-wrap">
38
+ <span class="text-surface-700 text-sm">
39
+ {{ t("miniAppLang.requiredPermissions") }}:
40
+ </span>
41
+ <div
42
+ v-for="requiredPermission in page.requiredPermissions"
43
+ class="bg-slate-300 px-2 py-0.5 rounded-md text-xs font-medium text-surface-600"
44
+ >
45
+ {{ requiredPermission }}
46
+ </div>
47
+ </div>
48
+ </template>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </TabPanel>
53
+ <TabPanel value="scopes">
54
+ <MiniAppFeatureScope :miniApp="miniApp" />
55
+ </TabPanel>
56
+ </TabPanels>
57
+ </Tabs>
58
+ </template>
59
+ <script setup lang="ts">
60
+ import { MiniAppDetail } from "~/simpleapp/generate/openapi";
61
+ import MiniAppPageIcon from "./MiniAppPageIcon.vue";
62
+ import MiniAppFeatureScope from "./MiniAppFeatureScope.vue";
63
+ import _ from "lodash";
64
+
65
+ const props = defineProps<{
66
+ miniApp: MiniAppDetail;
67
+ }>();
68
+ </script>
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div class="mb-8 text-surface-500">
3
+ {{ t("miniAppLang.scopeDescription") }}
4
+ </div>
5
+ <div class="space-y-3">
6
+ <div
7
+ v-for="(scopeList, resourceName) in scopes"
8
+ class="rounded-lg space-y-2"
9
+ >
10
+ <div class="font-semibold">
11
+ {{ t(resourceName.toLowerCase()) }}
12
+ </div>
13
+
14
+ <div class="grid grid-cols-2 gap-2">
15
+ <div
16
+ v-for="scope in scopeList"
17
+ class="space-x-2 text-sm bg-slate-100 rounded px-2 py-1 text-surface-600 font-medium"
18
+ >
19
+ <span>{{ _.startCase(scope) }}</span>
20
+ </div>
21
+ </div>
22
+
23
+ <Divider type="dashed" class="!mt-6 !mb-4" />
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script setup lang="ts">
29
+ import { MiniAppDetail } from "~/simpleapp/generate/openapi";
30
+ import _ from "lodash";
31
+
32
+ const props = defineProps<{
33
+ miniApp: MiniAppDetail;
34
+ }>();
35
+
36
+ const scopes = computed(() => {
37
+ if (!props?.miniApp?.integration?.scopes) {
38
+ return {};
39
+ }
40
+
41
+ const grouped: Record<string, string[]> = {};
42
+
43
+ for (const item of props?.miniApp?.integration?.scopes) {
44
+ const [prefix, suffix] = item.split(".");
45
+ if (!grouped[prefix]) {
46
+ grouped[prefix] = [];
47
+ }
48
+ grouped[prefix].push(suffix);
49
+ }
50
+
51
+ return grouped;
52
+ });
53
+ </script>