Skip to content

Commit 1dd3cfb

Browse files
committed
feat(ui): improve app component
1 parent 289f668 commit 1dd3cfb

File tree

4 files changed

+321
-10
lines changed

4 files changed

+321
-10
lines changed

web/src/App.vue

Lines changed: 156 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
save-button-text="Create"
6868
:title="$t('newProject')"
6969
event-name="i-project"
70+
@close="onNewProjectDialogueClosed()"
7071
>
7172
<template v-slot:form="{ onSave, onError, needSave, needReset }">
7273
<ProjectForm
@@ -80,6 +81,35 @@
8081
</template>
8182
</EditDialog>
8283

84+
<EditDialog
85+
v-model="subscriptionDialog"
86+
:save-button-text="user.admin && !user.has_active_subscription ? 'Activate' : 'Reactivate'"
87+
v-if="user"
88+
event-name="i-user"
89+
dont-close-on-save
90+
>
91+
<template v-slot:title="{}">
92+
<v-icon
93+
large
94+
class="mr-2"
95+
color="#f14668"
96+
>
97+
mdi-professional-hexagon
98+
</v-icon>
99+
Subscription details
100+
</template>
101+
102+
<template v-slot:form="{ onSave, onError, needSave, needReset }">
103+
<SubscriptionForm
104+
item-id="new"
105+
@save="onSave(); onSubscriptionKeyUpdates();"
106+
@error="onError"
107+
:need-save="needSave"
108+
:need-reset="needReset"
109+
/>
110+
</template>
111+
</EditDialog>
112+
83113
<EditDialog
84114
v-model="restoreProjectDialog"
85115
save-button-text="Restore"
@@ -174,8 +204,10 @@
174204
<v-list-item-content>{{ item.name }}</v-list-item-content>
175205
</v-list-item>
176206

207+
<v-divider v-if="user.can_create_project"/>
208+
177209
<v-list-item
178-
@click="newProjectDialog = true; newProjectType = '';"
210+
@click="showNewProjectDialogue()"
179211
v-if="user.can_create_project"
180212
data-testid="sidebar-newProject"
181213
>
@@ -364,6 +396,25 @@
364396
<template v-slot:append>
365397
<v-list class="pa-0">
366398

399+
<v-list-item
400+
key="premium"
401+
v-if="user.admin && !user.has_active_subscription"
402+
@click="subscriptionDialog = true"
403+
class="ActivatePremiumSubscriptionButton"
404+
>
405+
<v-list-item-content>
406+
<v-list-item-title
407+
style="font-weight: bold; color: white; font-size: 18px; text-align: center;"
408+
>
409+
<v-icon
410+
color="white"
411+
x-large
412+
>mdi-professional-hexagon</v-icon>
413+
Activate Subscription
414+
</v-list-item-title>
415+
</v-list-item-content>
416+
</v-list-item>
417+
367418
<v-list-item>
368419
<v-switch
369420
class="DarkModeSwitch"
@@ -458,6 +509,20 @@
458509

459510
<v-divider/>
460511

512+
<v-list-item
513+
key="runners"
514+
to="/runners"
515+
v-if="user.admin"
516+
>
517+
<v-list-item-icon>
518+
<v-icon>mdi-cogs</v-icon>
519+
</v-list-item-icon>
520+
521+
<v-list-item-content>
522+
{{ $t('runners') }}
523+
</v-list-item-content>
524+
</v-list-item>
525+
461526
<v-list-item
462527
key="tasks"
463528
to="/tasks"
@@ -473,16 +538,21 @@
473538
</v-list-item>
474539

475540
<v-list-item
476-
key="runners"
477-
to="/runners"
541+
key="subscription"
478542
v-if="user.admin"
543+
@click="subscriptionDialog = true"
479544
>
480545
<v-list-item-icon>
481-
<v-icon>mdi-cogs</v-icon>
546+
<v-icon
547+
color="#f14668"
548+
style="transform: scale(1.4)"
549+
>
550+
mdi-professional-hexagon
551+
</v-icon>
482552
</v-list-item-icon>
483553

484554
<v-list-item-content>
485-
{{ $t('runners') }}
555+
Subscription details
486556
</v-list-item-content>
487557
</v-list-item>
488558

@@ -604,6 +674,32 @@
604674
<v-app v-else></v-app>
605675
</template>
606676
<style lang="scss">
677+
.NewProSubscriptionMenuItem {
678+
transition: 0.2s transform;
679+
.v-list-item__content, .v-list-item__icon {
680+
transition: 0.5s transform;
681+
}
682+
&:hover {
683+
684+
transform: scale(1.05) translateY(-1px);
685+
686+
// .v-list-item__content {
687+
// transform: scale(1.05) translateX(2px);
688+
// }
689+
.v-list-item__icon {
690+
// transform: rotate(-360deg);
691+
}
692+
}
693+
}
694+
.ActivatePremiumSubscriptionButton {
695+
background: hsl(348deg, 86%, 61%);
696+
transform: rotate(-5deg) scale(0.95);
697+
border-radius: 6px;
698+
transition: 0.2s transform;
699+
&:hover {
700+
transform: rotate(-5deg) scale(1);
701+
}
702+
}
607703
608704
.theme--dark {
609705
--highlighted-card-bg-color: #262626;
@@ -827,6 +923,8 @@ import ProjectForm from '@/components/ProjectForm.vue';
827923
import UserForm from '@/components/UserForm.vue';
828924
import EventBus from '@/event-bus';
829925
import socket from '@/socket';
926+
927+
import SubscriptionForm from '@/components/SubscriptionForm.vue';
830928
import RestoreProjectForm from '@/components/RestoreProjectForm.vue';
831929
import YesNoDialog from '@/components/YesNoDialog.vue';
832930
import TaskLogDialog from '@/components/TaskLogDialog.vue';
@@ -907,6 +1005,7 @@ function getSystemLang() {
9071005
export default {
9081006
name: 'App',
9091007
components: {
1008+
SubscriptionForm,
9101009
TaskLogDialog,
9111010
YesNoDialog,
9121011
RestoreProjectForm,
@@ -929,6 +1028,9 @@ export default {
9291028
newProjectType: '',
9301029
userDialog: null,
9311030
hideUserDialogButtons: false,
1031+
1032+
subscriptionDialog: null,
1033+
9321034
restoreProjectDialog: null,
9331035
restoreProjectResult: null,
9341036
restoreProjectResultDialog: null,
@@ -956,8 +1058,14 @@ export default {
9561058
async projects(val) {
9571059
if (val.length === 0
9581060
&& this.$route.path.startsWith('/project/')
959-
&& this.$route.path !== '/project/new') {
960-
await this.$router.push({ path: '/project/new' });
1061+
&& this.$route.path !== '/project/new'
1062+
&& this.$route.path !== '/project/premium'
1063+
) {
1064+
if (this.$route.query.new_project === 'premium') {
1065+
await this.$router.push({ path: '/project/premium' });
1066+
} else {
1067+
await this.$router.push({ path: '/project/new' });
1068+
}
9611069
}
9621070
},
9631071
@@ -970,6 +1078,10 @@ export default {
9701078
EventBus.$emit('i-show-task', { taskId });
9711079
}
9721080
}
1081+
1082+
if ((this.projects || []).length > 0 && this.$route.query.new_project) {
1083+
EventBus.$emit('i-new-project', { projectType: this.$route.query.new_project });
1084+
}
9731085
},
9741086
9751087
darkMode(val) {
@@ -1058,6 +1170,12 @@ export default {
10581170
this.drawer = true;
10591171
});
10601172
1173+
EventBus.$on('i-new-project', (e) => {
1174+
setTimeout(() => {
1175+
this.showNewProjectDialogue(e.projectType);
1176+
}, 500);
1177+
});
1178+
10611179
EventBus.$on('i-show-task', async (e) => {
10621180
if (parseInt(this.$route.query.t || '', 10) !== e.taskId) {
10631181
const query = { ...this.$route.query, t: e.taskId };
@@ -1147,7 +1265,7 @@ export default {
11471265
switch (e.action) {
11481266
case 'new':
11491267
case 'restore':
1150-
await this.selectProject(e.item.id);
1268+
await this.selectProject(e.item.id, { new_project: undefined });
11511269
break;
11521270
case 'delete':
11531271
if (this.projectId === e.item.id && this.projects.length > 0) {
@@ -1171,11 +1289,21 @@ export default {
11711289
await this.loadUserInfo();
11721290
},
11731291
1292+
showNewProjectDialogue(projectType = '') {
1293+
this.newProjectDialog = true;
1294+
this.newProjectType = projectType;
1295+
},
1296+
11741297
selectLanguage(lang) {
11751298
localStorage.setItem('lang', lang);
11761299
window.location.reload();
11771300
},
11781301
1302+
async onNewProjectDialogueClosed() {
1303+
const query = { ...this.$route.query, new_project: undefined };
1304+
await this.$router.replace({ query });
1305+
},
1306+
11791307
async onTaskLogDialogClosed() {
11801308
const query = { ...this.$route.query, t: undefined };
11811309
await this.$router.replace({ query });
@@ -1237,7 +1365,7 @@ export default {
12371365
}
12381366
},
12391367
1240-
async selectProject(projectId) {
1368+
async selectProject(projectId, overriderQuery = {}) {
12411369
this.userRole = (await axios({
12421370
method: 'get',
12431371
url: `/api/project/${projectId}/role`,
@@ -1249,7 +1377,25 @@ export default {
12491377
return;
12501378
}
12511379
1252-
await this.$router.push({ path: `/project/${projectId}` });
1380+
let query = {};
1381+
1382+
switch (this.$route.path) {
1383+
case '/project/new':
1384+
query.new_project = '';
1385+
break;
1386+
default:
1387+
break;
1388+
}
1389+
1390+
query = {
1391+
...query,
1392+
...overriderQuery,
1393+
};
1394+
1395+
await this.$router.push({
1396+
path: `/project/${projectId}${window.location.search}`,
1397+
query,
1398+
});
12531399
},
12541400
12551401
async loadProjects() {

web/src/assets/background.svg

Lines changed: 15 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)