@hostlink/nuxt-light 1.59.2 → 1.60.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.59.2",
4
+ "version": "1.60.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -264,6 +264,11 @@ const routes = [
264
264
  name: "User-setting-two-factor-auth",
265
265
  path: "two-factor-auth",
266
266
  file: "runtime/pages/User/setting/two-factor-auth.vue"
267
+ },
268
+ {
269
+ name: "User-setting-sessions",
270
+ path: "sessions",
271
+ file: "runtime/pages/User/setting/sessions.vue"
267
272
  }
268
273
  ]
269
274
  }
@@ -359,6 +364,7 @@ const module$1 = defineNuxtModule({
359
364
  nuxt.options.vite.resolve = nuxt.options.vite.resolve || {};
360
365
  nuxt.options.vite.resolve.alias = nuxt.options.vite.resolve.alias || {};
361
366
  nuxt.options.vite.resolve.alias["collect.js"] = "collect.js/dist/index.js";
367
+ nuxt.options.vite.resolve.alias["json-to-graphql-query"] = "json-to-graphql-query/lib/index.js";
362
368
  nuxt.options.app.head.link = nuxt.options.app.head.link || [];
363
369
  nuxt.options.app.head.link.push({
364
370
  rel: "stylesheet",
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,136 @@
1
+ <script setup>
2
+ import { q, m, useQuasar, useAsyncData } from "#imports";
3
+ const $q = useQuasar();
4
+ const { data: my, refresh } = await useAsyncData("user-sessions", async () => {
5
+ return await q({
6
+ my: {
7
+ sessions: true
8
+ }
9
+ }).then((res) => res.my);
10
+ });
11
+ const getDeviceIcon = (userAgent) => {
12
+ if (userAgent.includes("Mobile")) return "smartphone";
13
+ if (userAgent.includes("Tablet")) return "tablet";
14
+ return "desktop_mac";
15
+ };
16
+ const getLocationDisplay = (session) => {
17
+ if (session.location?.country) {
18
+ return `${session.location.country} ${session.ip}`;
19
+ }
20
+ return session.ip;
21
+ };
22
+ const getLocationCode = (session) => {
23
+ return session.location?.countryCode || "Unknown";
24
+ };
25
+ const revokeSession = async (jti) => {
26
+ $q.dialog({
27
+ title: "Confirm",
28
+ message: "Are you sure you want to revoke this session?",
29
+ cancel: true,
30
+ persistent: true
31
+ }).onOk(async () => {
32
+ try {
33
+ await m("revokeSession", {
34
+ jti
35
+ });
36
+ $q.notify({
37
+ type: "positive",
38
+ message: "Session revoked successfully."
39
+ });
40
+ await refresh();
41
+ } catch (error) {
42
+ $q.notify({
43
+ type: "negative",
44
+ message: "Failed to revoke session."
45
+ });
46
+ }
47
+ });
48
+ };
49
+ </script>
50
+
51
+ <template>
52
+ <div>
53
+
54
+ <q-list bordered separator>
55
+ <q-item-label header>This is a list of devices that have logged into your account. Revoke any sessions that
56
+ you do not recognize.</q-item-label>
57
+
58
+ <q-item v-for="session in my.sessions" :key="session.jti">
59
+ <q-item-section avatar>
60
+ <q-icon :name="getDeviceIcon(session.user_agent)" color="primary" size="lg" />
61
+ </q-item-section>
62
+
63
+ <q-item-section>
64
+ <q-item-label class="text-weight-bold">
65
+ {{ getLocationDisplay(session) }}
66
+ </q-item-label>
67
+ <q-item-label caption lines="2">
68
+ <div class="flex items-center q-my-xs">
69
+ <q-badge color="positive" label="active" />
70
+ <q-badge v-if="session.is_current" color="info" label="This device" class="q-ml-sm" />
71
+ </div>
72
+ <div class="q-mt-sm">
73
+ Last accessed on {{ session.last_access_time }}
74
+ </div>
75
+ <div v-if="session.location?.city" class="text-caption">
76
+ Seen in {{ getLocationCode(session) }}
77
+ </div>
78
+ </q-item-label>
79
+ </q-item-section>
80
+
81
+ <q-item-section side top>
82
+ <q-btn flat dense round icon="info" color="primary">
83
+ <q-popup-proxy anchor="top right" self="top left" :offset="[0, 10]">
84
+ <q-card style="min-width: 300px">
85
+ <q-card-section>
86
+ <div class="text-h6">Session Details</div>
87
+ </q-card-section>
88
+
89
+ <q-separator />
90
+
91
+ <q-card-section>
92
+ <div class="q-mb-md">
93
+ <div class="text-caption text-grey">Session ID</div>
94
+ <div class="text-body2">{{ session.jti }}</div>
95
+ </div>
96
+
97
+ <div class="q-mb-md">
98
+ <div class="text-caption text-grey">IP Address</div>
99
+ <div class="text-body2">{{ session.ip }}</div>
100
+ </div>
101
+
102
+ <div class="q-mb-md">
103
+ <div class="text-caption text-grey">Login Time</div>
104
+ <div class="text-body2">{{ session.login_dt }}</div>
105
+ </div>
106
+
107
+ <div v-if="session.location" class="q-mb-md">
108
+ <div class="text-caption text-grey">Location</div>
109
+ <div class="text-body2">
110
+ {{ session.location.city }}, {{ session.location.regionName }}, {{
111
+ session.location.country }}
112
+ </div>
113
+ </div>
114
+
115
+ <div class="q-mb-md">
116
+ <div class="text-caption text-grey">User Agent</div>
117
+ <div class="text-body2 text-break" style="font-size: 12px">{{ session.user_agent
118
+ }}</div>
119
+ </div>
120
+ </q-card-section>
121
+
122
+ <q-separator />
123
+
124
+ <q-card-actions align="right">
125
+ <q-btn flat label="Close" v-close-popup />
126
+ <q-btn flat label="Revoke" color="negative" :disable="session.is_current"
127
+ @click="revokeSession(session.jti)" />
128
+ </q-card-actions>
129
+ </q-card>
130
+ </q-popup-proxy>
131
+ </q-btn>
132
+ </q-item-section>
133
+ </q-item>
134
+ </q-list>
135
+ </div>
136
+ </template>
@@ -0,0 +1,3 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -28,6 +28,8 @@ const route = useRoute();
28
28
  to="/User/setting/favorite" exact />
29
29
 
30
30
  <q-route-tab name="menu" icon="sym_o_menu" :label="$t('Menu')" to="/User/setting/menu" exact />
31
+ <q-route-tab name="sessions" icon="sym_o_devices" :label="$t('Sessions')"
32
+ to="/User/setting/sessions" exact />
31
33
  </q-tabs>
32
34
  </template>
33
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "1.59.2",
3
+ "version": "1.60.0",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": {
6
6
  "type": "git",