@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 +1 -1
- package/dist/module.mjs +37 -2
- package/dist/runtime/components/L/Editor.vue +11 -0
- package/dist/runtime/pages/User/[user_id]/edit.vue +4 -1
- package/dist/runtime/pages/User/[user_id]/view.vue +1 -1
- package/dist/runtime/pages/page_not_found.vue +5 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
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: {
|
|
278
|
+
my: { granted: { __args: { right } } }
|
|
244
279
|
});
|
|
245
280
|
if (!my) return;
|
|
246
|
-
if (!my.
|
|
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) => {
|
|
@@ -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.
|
|
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>
|