Skip to content

Commit f5434b3

Browse files
committed
chore(webapp): migration to vuetify 3
AI-assisted changes. I played with everything I could think of on the website: direct debit donation account creation, login, 2fa enabled, change email, delete account domain list, filtering rrset creation and deletion scrolled through all pages of the web site
1 parent 541d894 commit f5434b3

58 files changed

Lines changed: 1024 additions & 636 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

www/webapp/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.DS_Store
22
node_modules
3+
.vite
34

45
/tests/e2e/videos/
56
/tests/e2e/screenshots/

www/webapp/package.json

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"serve": "vite preview",
88
"build": "vite build",
99
"lint": "eslint --ignore-path .gitignore --no-fix src/**/*.{vue,js,json}",
10-
"lint:fix": "eslint --ignore-path .gitignore --fix src/**/*.{vue,js,json}"
10+
"lint:fix": "eslint --ignore-path .gitignore --fix src/**/*.{vue,js,json}",
11+
"postinstall": "vue-demi-switch 3"
1112
},
1213
"type": "module",
1314
"engines": {
@@ -16,26 +17,30 @@
1617
"dependencies": {
1718
"@fontsource/roboto": "^5.0.3",
1819
"@mdi/js": "~7.4.47",
20+
"@vuelidate/core": "^2.0.3",
21+
"@vuelidate/validators": "^2.0.4",
1922
"axios": "^1.4.0",
2023
"date-fns": "^4.1.0",
2124
"pinia": "^2.0.30",
22-
"vue": "~2.7.14",
23-
"vue-router": "~3.6.5",
24-
"vuelidate": "^0.7.7",
25-
"vuetify": "^2.7.0"
25+
"vue": "^3.4.19",
26+
"vue-router": "^4.3.0",
27+
"vuetify": "^3.7.5"
2628
},
2729
"devDependencies": {
2830
"@vitejs/plugin-legacy": "^6.0.0",
29-
"@vitejs/plugin-vue2": "^2.3.3",
31+
"@vitejs/plugin-vue": "^5.2.0",
3032
"eslint": "^8.45.0",
3133
"eslint-import-resolver-alias": "^1.1.2",
3234
"eslint-plugin-import": "^2.27.5",
3335
"eslint-plugin-vue": "^9.15.1",
3436
"eslint-plugin-vue-scoped-css": "^2.6.1",
35-
"eslint-plugin-vuetify": "^1.1.0",
37+
"eslint-plugin-vuetify": "^2.1.1",
3638
"sass": "~1.83.4",
37-
"unplugin-vue-components": "^28.0.0",
3839
"vite": "^6.0.11",
39-
"vuetify-loader": "~1.9.1"
40+
"vite-plugin-vuetify": "^2.0.4",
41+
"vue-demi": "^0.14.10"
42+
},
43+
"overrides": {
44+
"vue-demi": "^0.14.10"
4045
}
4146
}

www/webapp/src/App.vue

Lines changed: 127 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,91 @@
11
<template>
22
<v-app id="inspire">
33
<v-navigation-drawer
4-
v-model="drawer"
5-
app
6-
right
7-
disable-resize-watcher
4+
v-model="drawer"
5+
app
6+
location="right"
7+
disable-resize-watcher
88
>
9-
<v-list dense>
9+
<v-list density="compact">
1010
<v-list-item
11-
v-for="(item, key) in menu"
12-
:key="key"
13-
link
14-
:to="{name: item.name}"
15-
:exact="true">
16-
<v-list-item-action>
17-
<v-icon>{{ item.icon }}</v-icon>
18-
</v-list-item-action>
19-
<v-list-item-content>
20-
<v-list-item-title>
21-
{{ item.text }}
22-
<v-icon :color="item.post_icon_color" class="text--darken-2" small v-if="item.post_icon">{{ item.post_icon }}</v-icon>
23-
</v-list-item-title>
24-
</v-list-item-content>
11+
v-for="(item, key) in menu"
12+
:key="key"
13+
:to="{name: item.name}"
14+
:exact="true"
15+
>
16+
<template #prepend>
17+
<v-icon :icon="item.icon" />
18+
</template>
19+
<v-list-item-title>
20+
{{ item.text }}
21+
<v-icon v-if="item.post_icon" :icon="item.post_icon" :color="item.post_icon_color" size="small" />
22+
</v-list-item-title>
2523
</v-list-item>
2624
</v-list>
2725
</v-navigation-drawer>
2826

29-
<v-app-bar app class="white">
30-
<v-toolbar-title><router-link :to="{name: 'home'}">
27+
<v-app-bar app color="white" :extended="authenticated">
28+
<v-app-bar-title><router-link :to="{name: 'home'}">
3129
<v-img
32-
src="./assets/logo.svg"
33-
alt="deSEC Logo"
34-
eager
35-
contain
30+
src="./assets/logo.svg"
31+
alt="deSEC Logo"
32+
class="app-logo"
33+
height="32"
34+
eager
35+
contain
3636
></v-img>
37-
</router-link></v-toolbar-title>
37+
</router-link></v-app-bar-title>
3838
<v-spacer/>
3939
<div class="d-none d-md-block">
4040
<span class="mx-2" v-for="(item, key) in menu" :key="key">
4141
<router-link
42-
class="primary--text text--darken-2"
43-
:to="{name: item.name}"
42+
class="text-primary"
43+
:to="{name: item.name}"
4444
>{{ item.text }}</router-link>
45-
<v-icon :color="item.post_icon_color" class="ml-1 text--darken-1" small v-if="item.post_icon">{{ item.post_icon }}</v-icon>
45+
<v-icon v-if="item.post_icon" :icon="item.post_icon" :color="item.post_icon_color" class="ml-1" size="small" />
4646
</span>
4747
</div>
48-
<v-btn class="mx-4" color="primary" depressed :to="{name: 'signup', query: $route.query}" v-if="!user.authenticated">Create Account</v-btn>
49-
<v-btn class="mx-4 mr-0" color="primary" depressed :to="{name: 'login'}" v-if="!user.authenticated">Log In</v-btn>
50-
<v-btn class="mx-4 mr-0" color="primary" depressed outlined @click="logout" v-if="user.authenticated">Log Out</v-btn>
48+
<v-btn class="mx-4" color="primary" variant="flat" :to="{name: 'signup', query: $route.query}" v-if="!authenticated">Create Account</v-btn>
49+
<v-btn class="mx-4 mr-0" color="primary" variant="flat" :to="{name: 'login'}" v-if="!authenticated">Log In</v-btn>
50+
<v-btn class="mx-4 mr-0" color="primary" variant="outlined" @click="logout" v-if="authenticated">Log Out</v-btn>
5151
<v-app-bar-nav-icon class="d-md-none" @click.stop="drawer = !drawer" />
52-
<template #extension v-if="user.authenticated">
53-
<v-tabs background-color="primary darken-1" fixed-tabs>
54-
<v-tab
55-
v-for="(item, key) in tabmenu"
56-
:key="key"
57-
:to="{name: item.name}"
58-
>
59-
{{ item.text }}
60-
</v-tab>
61-
<v-spacer></v-spacer>
62-
<v-menu
63-
bottom
64-
left
65-
>
66-
<template #activator="{ on }">
52+
<template #extension v-if="authenticated">
53+
<div class="d-flex align-center w-100 bg-primary text-white">
54+
<v-tabs v-model="activeTab" class="flex-grow-1 text-white" bg-color="primary" color="white" slider-color="white" grow>
55+
<v-tab
56+
v-for="(item, key) in tabmenu"
57+
:key="key"
58+
:value="item.name"
59+
:to="{name: item.name}"
60+
class="text-white"
61+
>
62+
{{ item.text }}
63+
</v-tab>
64+
</v-tabs>
65+
<v-menu location="bottom">
66+
<template #activator="{ props }">
6767
<v-btn
68-
text
69-
class="align-self-center mr-4"
70-
v-on="on"
68+
variant="text"
69+
color="white"
70+
class="align-self-center mr-4"
71+
v-bind="props"
7172
>
7273
more
73-
<v-icon right>{{ mdiMenuDown }}</v-icon>
74+
<v-icon :icon="mdiMenuDown" end />
7475
</v-btn>
7576
</template>
7677

77-
<v-list class="grey lighten-3">
78+
<v-list class="bg-grey-lighten-3">
7879
<v-list-item
79-
v-for="(item, key) in tabmenumore"
80-
:key="key"
81-
:to="{name: item.name}"
80+
v-for="(item, key) in tabmenumore"
81+
:key="key"
82+
:to="{name: item.name}"
8283
>
8384
{{ item.text }}
8485
</v-list-item>
8586
</v-list>
8687
</v-menu>
87-
</v-tabs>
88+
</div>
8889
</template>
8990
</v-app-bar>
9091

@@ -94,23 +95,22 @@
9495
<v-icon
9596
color="warning"
9697
size="36"
97-
>
98-
{{ alert.icon }}
99-
</v-icon>
98+
:icon="alert.icon"
99+
/>
100100
</template>
101101
{{ alert.teaser }}
102102
<template #actions>
103103
<v-btn
104104
color="primary"
105-
depressed
105+
variant="flat"
106106
:href="alert.href"
107107
v-if="alert.href"
108108
>
109109
{{ alert.button || 'More' }}
110110
</v-btn>
111111
<v-btn
112112
color="primary"
113-
text
113+
variant="text"
114114
@click="user.unalert(alert.id)"
115115
>
116116
Hide
@@ -127,9 +127,9 @@
127127
<router-view/>
128128
</v-main>
129129
<v-footer
130-
class="d-flex flex-column align-stretch pa-0 white--text text--darken-1 elevation-12"
130+
class="d-flex flex-column align-stretch pa-0 text-white elevation-12"
131131
>
132-
<div class="grey darken-3 d-sm-flex flex-row justify-space-between pa-4">
132+
<div class="bg-grey-darken-3 d-sm-flex flex-row justify-space-between pa-4">
133133
<div class="pa-2">
134134
<b>deSEC e.V.</b>
135135
</div>
@@ -141,7 +141,7 @@
141141
<div class="px-2"><router-link :to="{name: 'impressum'}">Legal Notice (Impressum)</router-link></div>
142142
</div>
143143
</div>
144-
<div class="grey darken-4 d-md-flex flex-row justify-space-between pa-6">
144+
<div class="bg-grey-darken-4 d-md-flex flex-row justify-space-between pa-6">
145145
<div>
146146
<p>{{ email }}</p>
147147
<p>
@@ -153,7 +153,7 @@
153153
<div>
154154
<p>
155155
Please <router-link :to="{name: 'donate'}">donate</router-link>!
156-
<v-icon color="red" class="text--darken-2" dense>{{ mdiHeart }}</v-icon>
156+
<v-icon :icon="mdiHeart" color="red" />
157157
</p>
158158
<p>
159159
European Bank Account:<br>
@@ -167,7 +167,7 @@
167167
</div>
168168
<div>
169169
<p>Vorstand</p>
170-
<p class="white--text text--darken-2">
170+
<p class="text-white">
171171
Nils Wisiol<br/>
172172
Peter Thomassen<br/>
173173
Wolfgang Studier<br/>
@@ -196,38 +196,10 @@ import {
196196
197197
export default {
198198
name: 'App',
199-
data: () => ({
200-
user: useUserStore(),
201-
drawer: false,
202-
email: import.meta.env.VITE_APP_EMAIL,
203-
mdiHeart,
204-
mdiMenuDown,
205-
tabmenu: {
206-
'domains': {
207-
'name': 'domains',
208-
'text': 'Domain Management',
209-
},
210-
'tokens': {
211-
'name': 'tokens',
212-
'text': 'Token Management',
213-
},
214-
},
215-
tabmenumore: {
216-
'totp': {
217-
'name': 'totp',
218-
'text': 'Manage 2-Factor Authentication',
219-
},
220-
'change-email': {
221-
'name': 'change-email',
222-
'text': 'Change Email Address',
223-
},
224-
'delete-account': {
225-
'name': 'delete-account',
226-
'text': 'Delete Account',
227-
},
228-
},
229-
}),
230199
computed: {
200+
authenticated() {
201+
return this.user?.authenticated;
202+
},
231203
menu: () => {
232204
const user = useUserStore();
233205
const menu_perma = {
@@ -277,6 +249,46 @@ export default {
277249
return {...menu_perma, ...menu_opt};
278250
},
279251
},
252+
data: () => ({
253+
user: useUserStore(),
254+
drawer: false,
255+
email: import.meta.env.VITE_APP_EMAIL,
256+
activeTab: null,
257+
mdiHeart,
258+
mdiMenuDown,
259+
tabmenu: {
260+
'domains': {
261+
'name': 'domains',
262+
'text': 'Domain Management',
263+
},
264+
'tokens': {
265+
'name': 'tokens',
266+
'text': 'Token Management',
267+
},
268+
},
269+
tabmenumore: {
270+
'totp': {
271+
'name': 'totp',
272+
'text': 'Manage 2-Factor Authentication',
273+
},
274+
'change-email': {
275+
'name': 'change-email',
276+
'text': 'Change Email Address',
277+
},
278+
'delete-account': {
279+
'name': 'delete-account',
280+
'text': 'Delete Account',
281+
},
282+
},
283+
}),
284+
watch: {
285+
$route: {
286+
immediate: true,
287+
handler(to) {
288+
this.activeTab = to?.name ?? null;
289+
},
290+
},
291+
},
280292
methods: {
281293
async logout() {
282294
await logout();
@@ -285,3 +297,21 @@ export default {
285297
}
286298
}
287299
</script>
300+
301+
<style>
302+
.v-application a {
303+
color: rgb(var(--v-theme-primary));
304+
text-decoration: none;
305+
}
306+
.v-application a:hover,
307+
.v-application a:focus {
308+
text-decoration: underline;
309+
}
310+
.v-application .bg-grey-darken-3 a,
311+
.v-application .bg-grey-darken-4 a {
312+
color: rgb(var(--v-theme-secondary));
313+
}
314+
.app-logo {
315+
width: auto;
316+
}
317+
</style>

0 commit comments

Comments
 (0)