@hostlink/nuxt-light 1.73.2 → 1.74.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/runtime/components/L/App.vue +0 -19
- package/dist/runtime/components/L/AppMain.d.vue.ts +3 -3
- package/dist/runtime/components/L/AppMain.vue +43 -10
- package/dist/runtime/components/L/AppMain.vue.d.ts +3 -3
- package/dist/runtime/components/L/FacebookButton.d.vue.ts +19 -3
- package/dist/runtime/components/L/FacebookButton.vue +73 -12
- package/dist/runtime/components/L/FacebookButton.vue.d.ts +19 -3
- package/dist/runtime/components/L/FavMenu.d.vue.ts +2 -0
- package/dist/runtime/components/L/FavMenu.vue +10 -2
- package/dist/runtime/components/L/FavMenu.vue.d.ts +2 -0
- package/dist/runtime/components/L/Form.d.vue.ts +29 -56
- package/dist/runtime/components/L/Form.vue +70 -80
- package/dist/runtime/components/L/Form.vue.d.ts +29 -56
- package/dist/runtime/components/L/FormLayout.d.vue.ts +36 -0
- package/dist/runtime/components/L/FormLayout.vue +36 -0
- package/dist/runtime/components/L/FormLayout.vue.d.ts +36 -0
- package/dist/runtime/components/L/Login.vue +1 -1
- package/dist/runtime/components/L/Menu.d.vue.ts +2 -0
- package/dist/runtime/components/L/Menu.vue +4 -4
- package/dist/runtime/components/L/Menu.vue.d.ts +2 -0
- package/dist/runtime/composables/useLight.d.ts +0 -4
- package/dist/runtime/formkit/Form.d.vue.ts +2 -2
- package/dist/runtime/formkit/Form.vue +15 -18
- package/dist/runtime/formkit/Form.vue.d.ts +2 -2
- package/dist/runtime/formkit/index.js +2 -0
- package/dist/runtime/locales/en.json +8 -2
- package/dist/runtime/locales/zh-hk.json +8 -2
- package/dist/runtime/pages/Role/[name]/update-child.vue +4 -1
- package/dist/runtime/pages/System/fs.vue +116 -15
- package/dist/runtime/pages/User/setting/index.vue +29 -12
- package/dist/runtime/pages/User/setting/information.vue +4 -28
- package/dist/runtime/pages/User/setting/open_id.vue +132 -91
- package/dist/runtime/pages/User/setting/two-factor-auth.vue +388 -143
- package/dist/runtime/pages/User/setting.vue +3 -4
- package/dist/runtime/types/form.d.ts +2 -0
- package/dist/runtime/types/form.js +0 -0
- package/dist/runtime/utils/filterMenuItems.d.ts +10 -0
- package/dist/runtime/utils/filterMenuItems.js +34 -0
- package/dist/runtime/utils/formLayout.d.ts +2 -0
- package/dist/runtime/utils/formLayout.js +7 -0
- package/dist/runtime/utils/socialSdk.d.ts +2 -0
- package/dist/runtime/utils/socialSdk.js +127 -0
- package/package.json +14 -14
- package/dist/runtime/pages/Role/add2.d.vue.ts +0 -3
- package/dist/runtime/pages/Role/add2.vue +0 -57
- package/dist/runtime/pages/Role/add2.vue.d.ts +0 -3
- package/dist/runtime/pages/System/test.d.vue.ts +0 -3
- package/dist/runtime/pages/System/test.vue +0 -13
- package/dist/runtime/pages/System/test.vue.d.ts +0 -3
|
@@ -1,32 +1,49 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { reset } from "@formkit/core";
|
|
3
|
+
import { m, notify, q } from "#imports";
|
|
3
4
|
const { my } = await q({
|
|
4
5
|
my: {
|
|
5
6
|
username: true,
|
|
6
7
|
email: true,
|
|
7
8
|
first_name: true,
|
|
8
|
-
last_name: true
|
|
9
|
+
last_name: true,
|
|
10
|
+
phone: true,
|
|
11
|
+
addr1: true,
|
|
12
|
+
addr2: true,
|
|
13
|
+
addr3: true
|
|
9
14
|
}
|
|
10
15
|
});
|
|
11
16
|
const onSubmit = async (data, form) => {
|
|
12
|
-
|
|
17
|
+
await m("updateMy", {
|
|
13
18
|
data: {
|
|
14
19
|
email: data.email,
|
|
15
20
|
first_name: data.first_name,
|
|
16
|
-
last_name: data.last_name
|
|
21
|
+
last_name: data.last_name,
|
|
22
|
+
phone: data.phone,
|
|
23
|
+
addr1: data.addr1,
|
|
24
|
+
addr2: data.addr2,
|
|
25
|
+
addr3: data.addr3
|
|
17
26
|
}
|
|
18
|
-
}).then(() => {
|
|
19
|
-
notify("Your profile has been updated");
|
|
20
|
-
reset(form, data);
|
|
21
27
|
});
|
|
28
|
+
notify("Your profile has been updated");
|
|
29
|
+
reset(form, data);
|
|
22
30
|
};
|
|
23
31
|
</script>
|
|
24
32
|
|
|
25
33
|
<template>
|
|
26
|
-
<FormKit type="l-form" :value="my" :bordered="false" @submit="onSubmit">
|
|
27
|
-
<
|
|
28
|
-
<FormKit type="l-input" label="
|
|
29
|
-
<FormKit type="l-input" label="
|
|
30
|
-
<FormKit type="l-input" label="
|
|
34
|
+
<FormKit type="l-form" layout="stack" :value="my" :bordered="false" @submit="onSubmit">
|
|
35
|
+
<div class="text-h6">{{ $t("Personal information") }}</div>
|
|
36
|
+
<FormKit type="l-input" label="Username" name="username" readonly />
|
|
37
|
+
<FormKit type="l-input" label="Email" name="email" validation="required|email" />
|
|
38
|
+
<FormKit type="l-input" label="First name" name="first_name" validation="required" />
|
|
39
|
+
<FormKit type="l-input" label="Last name" name="last_name" />
|
|
40
|
+
|
|
41
|
+
<q-separator spaced />
|
|
42
|
+
|
|
43
|
+
<div class="text-h6">{{ $t("Contact information") }}</div>
|
|
44
|
+
<FormKit type="l-input" label="Phone" name="phone" />
|
|
45
|
+
<FormKit type="l-input" label="Address1" name="addr1" />
|
|
46
|
+
<FormKit type="l-input" label="Address2" name="addr2" />
|
|
47
|
+
<FormKit type="l-input" label="Address3" name="addr3" />
|
|
31
48
|
</FormKit>
|
|
32
49
|
</template>
|
|
@@ -1,34 +1,10 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
my: {
|
|
6
|
-
phone: true,
|
|
7
|
-
addr1: true,
|
|
8
|
-
addr2: true,
|
|
9
|
-
addr3: true
|
|
10
|
-
}
|
|
2
|
+
import { navigateTo } from "#imports";
|
|
3
|
+
await navigateTo("/User/setting", {
|
|
4
|
+
replace: true
|
|
11
5
|
});
|
|
12
|
-
const onSubmit = (data, form) => {
|
|
13
|
-
return m("updateMy", {
|
|
14
|
-
data: {
|
|
15
|
-
phone: data.phone,
|
|
16
|
-
addr1: data.addr1,
|
|
17
|
-
addr2: data.addr2,
|
|
18
|
-
addr3: data.addr3
|
|
19
|
-
}
|
|
20
|
-
}).then(() => {
|
|
21
|
-
notify("Your information has been updated");
|
|
22
|
-
reset(form, data);
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
6
|
</script>
|
|
26
7
|
|
|
27
8
|
<template>
|
|
28
|
-
<
|
|
29
|
-
<FormKit type="l-input" label="Phone" name="phone"></FormKit>
|
|
30
|
-
<FormKit type="l-input" label="Address1" name="addr1"></FormKit>
|
|
31
|
-
<FormKit type="l-input" label="Address2" name="addr2"></FormKit>
|
|
32
|
-
<FormKit type="l-input" label="Address3" name="addr3"></FormKit>
|
|
33
|
-
</FormKit>
|
|
9
|
+
<div />
|
|
34
10
|
</template>
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
3
|
-
import { useQuasar } from "quasar";
|
|
2
|
+
import { nextTick, onMounted, reactive, ref } from "vue";
|
|
4
3
|
import { q, useLight } from "#imports";
|
|
5
4
|
import { getApiClient } from "@hostlink/light";
|
|
6
|
-
import { fabGoogle, fabFacebook, fabMicrosoft } from "@quasar/extras/fontawesome-
|
|
5
|
+
import { fabGoogle, fabFacebook, fabMicrosoft } from "@quasar/extras/fontawesome-v7";
|
|
6
|
+
import { loadGoogleIdentityServices } from "../../../utils/socialSdk";
|
|
7
7
|
const api = getApiClient();
|
|
8
8
|
const light = useLight();
|
|
9
|
-
const
|
|
10
|
-
let { app, my } = await q({
|
|
9
|
+
const response = await q({
|
|
11
10
|
app: {
|
|
12
11
|
googleClientId: true,
|
|
13
12
|
microsoftClientId: true,
|
|
@@ -20,123 +19,152 @@ let { app, my } = await q({
|
|
|
20
19
|
facebook: true
|
|
21
20
|
}
|
|
22
21
|
});
|
|
23
|
-
const
|
|
24
|
-
my = reactive(my);
|
|
25
|
-
const
|
|
22
|
+
const app = response.app;
|
|
23
|
+
const my = reactive(response.my);
|
|
24
|
+
const providerLoading = reactive({
|
|
25
|
+
google: false,
|
|
26
|
+
microsoft: false,
|
|
27
|
+
facebook: false
|
|
28
|
+
});
|
|
29
|
+
const googleSdkLoading = ref(false);
|
|
30
|
+
const googleSdkError = ref("");
|
|
31
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
32
|
+
const notifyError = (error) => {
|
|
33
|
+
light.notify({
|
|
34
|
+
message: errorMessage(error),
|
|
35
|
+
color: "negative",
|
|
36
|
+
icon: "sym_o_error"
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
const refreshAccounts = async () => {
|
|
40
|
+
const result = await q({
|
|
41
|
+
my: {
|
|
42
|
+
google: true,
|
|
43
|
+
microsoft: true,
|
|
44
|
+
facebook: true
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
Object.assign(my, result.my);
|
|
48
|
+
};
|
|
49
|
+
const handleGoogleCredentialResponse = async (credentialResponse) => {
|
|
50
|
+
if (!credentialResponse.credential || providerLoading.google) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
providerLoading.google = true;
|
|
26
54
|
try {
|
|
27
|
-
await api.auth.google.register(
|
|
28
|
-
|
|
29
|
-
my: { google: true }
|
|
30
|
-
});
|
|
31
|
-
my.google = resp.my.google;
|
|
55
|
+
await api.auth.google.register(credentialResponse.credential);
|
|
56
|
+
await refreshAccounts();
|
|
32
57
|
light.notify({
|
|
33
58
|
message: "Google account linked",
|
|
34
59
|
color: "positive"
|
|
35
60
|
});
|
|
36
|
-
} catch (
|
|
37
|
-
|
|
61
|
+
} catch (error) {
|
|
62
|
+
notifyError(error);
|
|
63
|
+
} finally {
|
|
64
|
+
providerLoading.google = false;
|
|
38
65
|
}
|
|
39
66
|
};
|
|
40
|
-
|
|
41
|
-
if (app.googleClientId) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
const initializeGoogle = async () => {
|
|
68
|
+
if (!app.googleClientId || my.google) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
googleSdkLoading.value = true;
|
|
72
|
+
googleSdkError.value = "";
|
|
73
|
+
try {
|
|
74
|
+
const google = await loadGoogleIdentityServices();
|
|
75
|
+
googleSdkLoading.value = false;
|
|
76
|
+
await nextTick();
|
|
77
|
+
const target = document.getElementById("g_id_signin");
|
|
78
|
+
if (!target || my.google) {
|
|
51
79
|
return;
|
|
52
80
|
}
|
|
53
|
-
|
|
54
|
-
nextTick(() => {
|
|
81
|
+
target.replaceChildren();
|
|
55
82
|
google.accounts.id.initialize({
|
|
56
83
|
client_id: app.googleClientId,
|
|
57
84
|
callback: handleGoogleCredentialResponse
|
|
58
85
|
});
|
|
59
|
-
google.accounts.id.renderButton(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
light.dialog({
|
|
74
|
-
title: "Unlink",
|
|
75
|
-
color: "negative",
|
|
76
|
-
message: "Are you sure you want to unlink your Google account?",
|
|
77
|
-
ok: "Yes",
|
|
78
|
-
cancel: "No"
|
|
79
|
-
}).onOk(async () => {
|
|
80
|
-
await api.auth.google.unlink();
|
|
81
|
-
my.gmail = null;
|
|
82
|
-
window.location.reload();
|
|
83
|
-
});
|
|
86
|
+
google.accounts.id.renderButton(target, {
|
|
87
|
+
type: "profile",
|
|
88
|
+
shape: "pill",
|
|
89
|
+
theme: "outline",
|
|
90
|
+
text: "signin_with",
|
|
91
|
+
size: "large",
|
|
92
|
+
logo_alignment: "left"
|
|
93
|
+
});
|
|
94
|
+
} catch (error) {
|
|
95
|
+
googleSdkError.value = errorMessage(error);
|
|
96
|
+
notifyError(error);
|
|
97
|
+
} finally {
|
|
98
|
+
googleSdkLoading.value = false;
|
|
99
|
+
}
|
|
84
100
|
};
|
|
85
|
-
const
|
|
101
|
+
const unlinkProvider = (provider, label, unlink) => {
|
|
86
102
|
light.dialog({
|
|
87
103
|
title: "Unlink",
|
|
88
104
|
color: "negative",
|
|
89
|
-
message:
|
|
105
|
+
message: `Are you sure you want to unlink your ${label} account?`,
|
|
90
106
|
ok: "Yes",
|
|
91
107
|
cancel: "No"
|
|
92
108
|
}).onOk(async () => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
109
|
+
providerLoading[provider] = true;
|
|
110
|
+
try {
|
|
111
|
+
await unlink();
|
|
112
|
+
await refreshAccounts();
|
|
113
|
+
light.notify({
|
|
114
|
+
message: `${label} account unlinked`,
|
|
115
|
+
color: "positive"
|
|
116
|
+
});
|
|
117
|
+
if (provider === "google") {
|
|
118
|
+
await initializeGoogle();
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
notifyError(error);
|
|
122
|
+
} finally {
|
|
123
|
+
providerLoading[provider] = false;
|
|
124
|
+
}
|
|
96
125
|
});
|
|
97
126
|
};
|
|
98
|
-
const
|
|
127
|
+
const onUnlinkGoogle = () => unlinkProvider("google", "Google", api.auth.google.unlink);
|
|
128
|
+
const onUnlinkMicrosoft = () => unlinkProvider("microsoft", "Microsoft", api.auth.microsoft.unlink);
|
|
129
|
+
const onUnlinkFacebook = () => unlinkProvider("facebook", "Facebook", api.auth.facebook.unlink);
|
|
130
|
+
const onLinkMicrosoft = async (microsoftResponse) => {
|
|
131
|
+
const accountId = microsoftResponse.account?.localAccountId;
|
|
132
|
+
if (!accountId || providerLoading.microsoft) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
providerLoading.microsoft = true;
|
|
99
136
|
try {
|
|
100
|
-
await api.auth.microsoft.register(
|
|
137
|
+
await api.auth.microsoft.register(accountId);
|
|
138
|
+
await refreshAccounts();
|
|
101
139
|
light.notify({
|
|
102
140
|
message: "Microsoft account linked",
|
|
103
141
|
color: "positive"
|
|
104
142
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
color: "negative"
|
|
110
|
-
});
|
|
143
|
+
} catch (error) {
|
|
144
|
+
notifyError(error);
|
|
145
|
+
} finally {
|
|
146
|
+
providerLoading.microsoft = false;
|
|
111
147
|
}
|
|
112
148
|
};
|
|
113
149
|
const onLinkFacebook = async (accessToken) => {
|
|
150
|
+
if (providerLoading.facebook) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
providerLoading.facebook = true;
|
|
114
154
|
try {
|
|
115
155
|
await api.auth.facebook.register(accessToken);
|
|
156
|
+
await refreshAccounts();
|
|
116
157
|
light.notify({
|
|
117
158
|
message: "Facebook account linked",
|
|
118
159
|
color: "positive"
|
|
119
160
|
});
|
|
120
|
-
} catch (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
161
|
+
} catch (error) {
|
|
162
|
+
notifyError(error);
|
|
163
|
+
} finally {
|
|
164
|
+
providerLoading.facebook = false;
|
|
125
165
|
}
|
|
126
166
|
};
|
|
127
|
-
|
|
128
|
-
light.dialog({
|
|
129
|
-
title: "Unlink",
|
|
130
|
-
color: "negative",
|
|
131
|
-
message: "Are you sure you want to unlink your Facebook account?",
|
|
132
|
-
ok: "Yes",
|
|
133
|
-
cancel: "No"
|
|
134
|
-
}).onOk(async () => {
|
|
135
|
-
await api.auth.facebook.unlink();
|
|
136
|
-
my.facebook = null;
|
|
137
|
-
window.location.reload();
|
|
138
|
-
});
|
|
139
|
-
};
|
|
167
|
+
onMounted(initializeGoogle);
|
|
140
168
|
const text1 = "Your social accounts are securely linked using industry-standard OAuth protocols. You can unlink them at any time.";
|
|
141
169
|
</script>
|
|
142
170
|
|
|
@@ -174,14 +202,21 @@ const text1 = "Your social accounts are securely linked using industry-standard
|
|
|
174
202
|
<div class="text-caption text-grey-6">{{ $t('Connected Account') }}</div>
|
|
175
203
|
<div class="text-body2 text-weight-medium q-mt-xs">{{ my.google }}</div>
|
|
176
204
|
</div>
|
|
177
|
-
<q-btn class="full-width" color="negative" outline @click="
|
|
178
|
-
:label="$t('Unlink Account')"
|
|
205
|
+
<q-btn class="full-width" color="negative" outline @click="onUnlinkGoogle"
|
|
206
|
+
icon="sym_o_link_off" :label="$t('Unlink Account')"
|
|
207
|
+
:loading="providerLoading.google" />
|
|
179
208
|
</template>
|
|
180
209
|
<template v-else>
|
|
181
210
|
<div class="text-center q-mb-md text-grey-6">
|
|
182
211
|
{{ $t('Click to link your Google account for quick sign-in') }}
|
|
183
212
|
</div>
|
|
184
|
-
<div
|
|
213
|
+
<div v-if="googleSdkLoading" class="flex justify-center q-pa-sm">
|
|
214
|
+
<q-spinner color="primary" size="32px" />
|
|
215
|
+
</div>
|
|
216
|
+
<q-banner v-else-if="googleSdkError" class="bg-red-1 text-negative">
|
|
217
|
+
{{ $t('Google login is not available') }}
|
|
218
|
+
</q-banner>
|
|
219
|
+
<div v-else id="g_id_signin" class="flex justify-center"></div>
|
|
185
220
|
</template>
|
|
186
221
|
</q-card-section>
|
|
187
222
|
<q-card-section v-else>
|
|
@@ -219,13 +254,17 @@ const text1 = "Your social accounts are securely linked using industry-standard
|
|
|
219
254
|
<div class="text-body2 text-weight-medium q-mt-xs">{{ my.microsoft }}</div>
|
|
220
255
|
</div>
|
|
221
256
|
<q-btn class="full-width" color="negative" outline @click="onUnlinkMicrosoft"
|
|
222
|
-
icon="sym_o_link_off" :label="$t('Unlink Account')"
|
|
257
|
+
icon="sym_o_link_off" :label="$t('Unlink Account')"
|
|
258
|
+
:loading="providerLoading.microsoft" />
|
|
223
259
|
</template>
|
|
224
260
|
<template v-else>
|
|
225
261
|
<div class="text-center q-mb-md text-grey-6">
|
|
226
262
|
{{ $t('Click to link your Microsoft account for quick sign-in') }}
|
|
227
263
|
</div>
|
|
228
|
-
<div class="flex justify-center">
|
|
264
|
+
<div v-if="providerLoading.microsoft" class="flex justify-center q-pa-sm">
|
|
265
|
+
<q-spinner color="primary" size="32px" />
|
|
266
|
+
</div>
|
|
267
|
+
<div v-else class="flex justify-center">
|
|
229
268
|
<l-microsoft-button :client-id="app.microsoftClientId"
|
|
230
269
|
:tenant-id="app.microsoftTenantId" @login="onLinkMicrosoft" />
|
|
231
270
|
</div>
|
|
@@ -266,14 +305,16 @@ const text1 = "Your social accounts are securely linked using industry-standard
|
|
|
266
305
|
<div class="text-body2 text-weight-medium q-mt-xs">{{ my.facebook }}</div>
|
|
267
306
|
</div>
|
|
268
307
|
<q-btn class="full-width" color="negative" outline @click="onUnlinkFacebook"
|
|
269
|
-
icon="sym_o_link_off" :label="$t('Unlink Account')"
|
|
308
|
+
icon="sym_o_link_off" :label="$t('Unlink Account')"
|
|
309
|
+
:loading="providerLoading.facebook" />
|
|
270
310
|
</template>
|
|
271
311
|
<template v-else>
|
|
272
312
|
<div class="text-center q-mb-md text-grey-6">
|
|
273
313
|
{{ $t('Click to link your Facebook account for quick sign-in') }}
|
|
274
314
|
</div>
|
|
275
315
|
<div class="flex justify-center">
|
|
276
|
-
<l-facebook-button
|
|
316
|
+
<l-facebook-button :app-id="app.facebookAppId"
|
|
317
|
+
:disable="providerLoading.facebook" @login="onLinkFacebook" />
|
|
277
318
|
</div>
|
|
278
319
|
</template>
|
|
279
320
|
</q-card-section>
|