@hostlink/nuxt-light 1.70.1 → 1.71.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.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "1.70.1",
4
+ "version": "1.71.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -189,6 +189,17 @@ const module$1 = defineNuxtModule({
189
189
  });
190
190
  }
191
191
  });
192
+ extendPages((pages) => {
193
+ const markIndex = (route) => {
194
+ if (route.file && /(?:\/|\\)index\.vue$/.test(route.file)) {
195
+ route.meta = { ...route.meta ?? {}, isIndex: true };
196
+ }
197
+ if (route.children) {
198
+ for (const child of route.children) markIndex(child);
199
+ }
200
+ };
201
+ for (const p of pages) markIndex(p);
202
+ });
192
203
  nuxt.options.imports = nuxt.options.imports || {};
193
204
  nuxt.options.imports.presets = nuxt.options.imports.presets || [];
194
205
  nuxt.options.imports.presets.push({ from: "quasar", imports: ["useQuasar"] });
@@ -239,11 +250,35 @@ export default defineNuxtPlugin(() => {
239
250
  const normalize = (p) => (p || "").replace(/[/]+$/, "");
240
251
  const publicPaths = ["/", "/page_not_found", "/login"].map(normalize);
241
252
  if (publicPaths.includes(normalize(to.path))) return;
253
+
254
+ // Allow the page to override the required permission via definePageMeta({ permission: '...' })
255
+ let right = to.meta.permission;
256
+ if (!right) {
257
+ const segments = to.path
258
+ .replace(/\\/+$/, "")
259
+ .split("/")
260
+ .filter(Boolean)
261
+ .filter((segment) => !segment.startsWith(":") && !/^\\d+$/.test(segment))
262
+ .map((segment) => segment.toLowerCase());
263
+ right = segments.join(".");
264
+ // If the matched route (or any nested match) is an index.vue
265
+ // leaf, treat the URL as a folder-index page and append .index.
266
+ // Vue Router 4 merges meta with the leaf winning on primitives, so
267
+ // nested cases like /User/setting (parent: setting.vue, child:
268
+ // setting/index.vue) still resolve to user.setting.index.
269
+ if (right && to.meta.isIndex) {
270
+ right = right + ".index";
271
+ }
272
+ }
273
+ right = right || "";
274
+
275
+ if (!right) return;
276
+
242
277
  const { my } = await q({
243
- my: { allowedPath: { __args: { path: to.path } } }
278
+ my: { granted: { __args: { right } } }
244
279
  });
245
280
  if (!my) return;
246
- if (!my.allowedPath) {
281
+ if (!my.granted) {
247
282
  return "/page_not_found?path=" + encodeURIComponent(to.fullPath);
248
283
  }
249
284
  }, { global: true });
@@ -150,12 +150,23 @@ const updateSelectionState = (e) => {
150
150
  const onEditorClick = (e) => {
151
151
  updateSelectionState(e);
152
152
  };
153
+ let dialogOpening = false;
153
154
  const onEditorDblClick = (e) => {
155
+ e.stopPropagation();
156
+ if (dialogOpening) return;
154
157
  updateSelectionState(e);
155
158
  if (selectedImageNode.value) {
159
+ dialogOpening = true;
156
160
  insertEditImageCMD();
161
+ setTimeout(() => {
162
+ dialogOpening = false;
163
+ }, 300);
157
164
  } else if (selectedLinkNode.value) {
165
+ dialogOpening = true;
158
166
  insertEditLinkCMD();
167
+ setTimeout(() => {
168
+ dialogOpening = false;
169
+ }, 300);
159
170
  }
160
171
  };
161
172
  const openInsertEditImageDialog = (initialSource = "", skipSaveCaret = false) => {
@@ -1,5 +1,8 @@
1
1
  <script setup>
2
- import { q, useObject } from "#imports";
2
+ import { q, useObject, definePageMeta } from "#imports";
3
+ definePageMeta({
4
+ permission: "user.update"
5
+ });
3
6
  const { data: obj } = await useObject({
4
7
  username: true,
5
8
  first_name: true,
@@ -35,7 +35,7 @@ const reset2fa = async () => {
35
35
  <template>
36
36
  <l-page :edit-btn="obj.canUpdate" v-if="obj">
37
37
  <template #header>
38
- <l-btn to="change-password" icon="sym_o_key" permission="user.changePassword"
38
+ <l-btn to="change-password" icon="sym_o_key" permission="user.change-password"
39
39
  label="Change password"></l-btn>
40
40
  <l-btn to="update-role" icon="sym_o_people" permission="user.role.add" label="Update role"></l-btn>
41
41
  <l-btn label="Reset 2FA" icon="sym_o_key" permission="user.reset2fa" @click="reset2fa"></l-btn>
@@ -2,6 +2,9 @@
2
2
  import { useRoute, navigateTo } from "#imports";
3
3
  const route = useRoute();
4
4
  const attemptedPath = route.query.path || route.fullPath;
5
+ const retry = async () => {
6
+ await navigateTo(attemptedPath, { replace: true });
7
+ };
5
8
  </script>
6
9
 
7
10
  <template>
@@ -19,8 +22,9 @@ const attemptedPath = route.query.path || route.fullPath;
19
22
  The requested page was not found or you do not have permission to access it.
20
23
  </div>
21
24
  </q-banner>
22
- <div class="q-mt-md">
25
+ <div class="q-mt-md q-gutter-sm">
23
26
  <q-btn color="primary" icon="sym_o_home" label="Home" to="/" />
27
+ <q-btn v-if="attemptedPath && attemptedPath !== '/'" color="secondary" icon="sym_o_refresh" label="Retry" @click="retry" />
24
28
  </div>
25
29
  </l-page>
26
30
  </template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "1.70.1",
3
+ "version": "1.71.0",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": {
6
6
  "type": "git",