Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3baacd3

Browse files
satellite/admin-ui: add account freeze functionalities
This adds UI functionality to freeze an account and view its freeze status. Issue: #7616 Change-Id: Ibc80b828b99c12a7d52570ae1d5d330dbcc378f1
1 parent 9363da3 commit 3baacd3

File tree

11 files changed

+369
-198
lines changed

11 files changed

+369
-198
lines changed

satellite/admin/back-office/ui/src/App.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ import { VSkeletonLoader } from 'vuetify/components';
2626
2727
import { useAppStore } from '@/store/app';
2828
import { useNotificationsStore } from '@/store/notifications';
29+
import { useUsersStore } from '@/store/users';
2930
3031
import Notifications from '@/layouts/default/Notifications.vue';
3132
3233
const appStore = useAppStore();
34+
const usersStore = useUsersStore();
3335
const notify = useNotificationsStore();
3436
3537
onMounted(async () => {
3638
try {
3739
await Promise.all([
38-
appStore.getSettings(),
40+
usersStore.getAccountFreezeTypes(),appStore.getSettings(),
3941
appStore.getPlacements(),
4042
]);
4143
} catch (error) {

satellite/admin/back-office/ui/src/components/AccountActionsMenu.vue

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
<template>
55
<v-menu activator="parent">
66
<v-list class="pa-2">
7-
<v-list-item v-if="featureFlags.account.view" density="comfortable" link rounded="lg" base-color="info" router-link to="/account-details">
7+
<v-list-item v-if="featureFlags.account.view && !isCurrentRouteViewAccount" density="comfortable" link rounded="lg" base-color="info" @click="viewAccount">
88
<v-list-item-title class="text-body-2 font-weight-medium">
99
View Account
1010
</v-list-item-title>
1111
</v-list-item>
1212

13-
<v-divider v-if="featureFlags.account.updateInfo || featureFlags.account.updateStaus || featureFlags.account.updateValueAttribution || featureFlags.account.updatePlacement || featureFlags.account.updateLimits || featureFlags.project.create " class="my-2" />
13+
<v-divider v-if="featureFlags.account.updateInfo || featureFlags.account.updateStatus || featureFlags.account.updateValueAttribution || featureFlags.account.updatePlacement || featureFlags.account.updateLimits || featureFlags.project.create " class="my-2" />
1414

1515
<v-list-item v-if="featureFlags.account.updateInfo" density="comfortable" link rounded="lg">
1616
<v-list-item-title class="text-body-2 font-weight-medium">
@@ -63,10 +63,12 @@
6363
</v-list-item-title>
6464
</v-list-item>
6565

66-
<v-list-item v-if="featureFlags.account.suspend" density="comfortable" link rounded="lg" base-color="warning">
67-
<v-list-item-title class="text-body-2 font-weight-medium">
68-
Suspend
69-
<AccountSuspendDialog />
66+
<v-list-item
67+
v-if="featureFlags.account.suspend || featureFlags.account.unsuspend"
68+
density="comfortable" link rounded="lg" base-color="warning"
69+
>
70+
<v-list-item-title class="text-body-2 font-weight-medium" @click="emit('toggleFreeze', user)">
71+
{{ user.freezeStatus ? "Unfreeze" : "Freeze" }}
7072
</v-list-item-title>
7173
</v-list-item>
7274

@@ -82,19 +84,40 @@
8284

8385
<script setup lang="ts">
8486
import { VMenu, VList, VListItem, VListItemTitle, VDivider } from 'vuetify/components';
87+
import { computed } from 'vue';
88+
import { useRouter } from 'vue-router';
8589
86-
import { FeatureFlags } from '@/api/client.gen';
90+
import { FeatureFlags, UserAccount } from '@/api/client.gen';
8791
import { useAppStore } from '@/store/app';
92+
import { ROUTES } from '@/router';
8893
8994
import AccountInformationDialog from '@/components/AccountInformationDialog.vue';
9095
import AccountStatusDialog from '@/components/AccountStatusDialog.vue';
9196
import AccountResetMFADialog from '@/components/AccountResetMFADialog.vue';
92-
import AccountSuspendDialog from '@/components/AccountSuspendDialog.vue';
9397
import AccountDeleteDialog from '@/components/AccountDeleteDialog.vue';
9498
import AccountNewProjectDialog from '@/components/AccountNewProjectDialog.vue';
9599
import AccountGeofenceDialog from '@/components/AccountGeofenceDialog.vue';
96100
import AccountUserAgentsDialog from '@/components/AccountUserAgentsDialog.vue';
97101
import AccountLimitsDialog from '@/components/AccountLimitsDialog.vue';
98102
99-
const featureFlags = useAppStore().state.settings.admin.features as FeatureFlags;
103+
const appStore = useAppStore();
104+
const router = useRouter();
105+
106+
const props = defineProps<{
107+
user: UserAccount;
108+
}>();
109+
110+
const featureFlags = computed(() => appStore.state.settings.admin.features as FeatureFlags);
111+
112+
const isCurrentRouteViewAccount = computed(() => {
113+
return router.currentRoute.value.name === ROUTES.Account.name;
114+
});
115+
116+
const emit = defineEmits<{
117+
(e: 'toggleFreeze', user: UserAccount): void;
118+
}>();
119+
120+
function viewAccount() {
121+
router.push({ name: ROUTES.Account.name, params: { email: props.user.email } });
122+
}
100123
</script>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (C) 2023 Storj Labs, Inc.
2+
// See LICENSE for copying information.
3+
4+
<template>
5+
<v-dialog v-model="model" width="400" transition="fade-transition">
6+
<v-card rounded="xlg">
7+
<template #title>
8+
Freeze Account
9+
</template>
10+
<template #subtitle>
11+
Select the freeze type to apply.
12+
</template>
13+
<template #append>
14+
<v-btn :icon="X" variant="text" size="small" color="default" @click="model = false" />
15+
</template>
16+
17+
<v-form class="pa-6">
18+
<v-row>
19+
<v-col cols="12">
20+
<v-select
21+
v-model="freezeType"
22+
label="Freeze type" placeholder="Select freeze type"
23+
:items="freezeTypes"
24+
item-title="name" item-value="value"
25+
hide-details="auto"
26+
variant="solo-filled"
27+
flat required
28+
/>
29+
</v-col>
30+
</v-row>
31+
</v-form>
32+
33+
<v-card-actions class="pa-6">
34+
<v-row>
35+
<v-col>
36+
<v-btn
37+
variant="outlined" color="default"
38+
:disabled="isLoading"
39+
block
40+
@click="model = false"
41+
>
42+
Cancel
43+
</v-btn>
44+
</v-col>
45+
<v-col>
46+
<v-btn
47+
color="warning" variant="flat"
48+
:loading="isLoading"
49+
:disabled="freezeType === undefined"
50+
block
51+
@click="freezeAccount"
52+
>
53+
Freeze Account
54+
</v-btn>
55+
</v-col>
56+
</v-row>
57+
</v-card-actions>
58+
</v-card>
59+
</v-dialog>
60+
</template>
61+
62+
<script setup lang="ts">
63+
import { computed, ref, watch } from 'vue';
64+
import {
65+
VDialog,
66+
VCard,
67+
VBtn,
68+
VForm,
69+
VRow,
70+
VCol,
71+
VSelect,
72+
VCardActions,
73+
} from 'vuetify/components';
74+
import { X } from 'lucide-vue-next';
75+
76+
import { UserAccount } from '@/api/client.gen';
77+
import { useUsersStore } from '@/store/users';
78+
import { useLoading } from '@/composables/useLoading';
79+
import { useNotificationsStore } from '@/store/notifications';
80+
81+
const usersStore = useUsersStore();
82+
83+
const { isLoading, withLoading } = useLoading();
84+
const notify = useNotificationsStore();
85+
86+
const freezeType = ref<number>();
87+
88+
const model = defineModel<boolean>({ required: true });
89+
90+
const props = defineProps<{
91+
account: UserAccount;
92+
}>();
93+
94+
const freezeTypes = computed(() => usersStore.state.freezeTypes);
95+
96+
function freezeAccount() {
97+
withLoading(async () => {
98+
if (freezeType.value === undefined) {
99+
return;
100+
}
101+
try {
102+
await usersStore.freezeUser(props.account.id, freezeType.value);
103+
notify.notifySuccess('Account frozen successfully.');
104+
model.value = false;
105+
106+
await usersStore.getUserByEmail(props.account.email);
107+
} catch (error) {
108+
notify.notifyError(`Failed to freeze account. ${error.message}`);
109+
return;
110+
}
111+
});
112+
}
113+
114+
watch(() => model.value, (newVal) => {
115+
if (!newVal) {
116+
freezeType.value = undefined;
117+
}
118+
});
119+
</script>

satellite/admin/back-office/ui/src/components/AccountProjectsTableComponent.vue

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@
9595
<v-tooltip>
9696
{{ item.segment.used !== null ? item.segment.used.toLocaleString() + '/' : 'Limit:' }}
9797
{{ item.segment.limit.toLocaleString() }}
98-
<template #activator="{ props }">
98+
<template #activator="{ props: activatorProps }">
9999
<v-chip
100100
v-if="item.segment.percent !== null"
101-
v-bind="props"
101+
v-bind="activatorProps"
102102
variant="tonal"
103103
:color="getPercentColor(item.segment.percent)"
104104
size="small"
@@ -107,7 +107,7 @@
107107
>
108108
{{ item.segment.percent }}&percnt;
109109
</v-chip>
110-
<v-icon v-else icon="mdi-alert-circle-outline" color="error" v-bind="props" />
110+
<v-icon v-else icon="mdi-alert-circle-outline" color="error" v-bind="activatorProps" />
111111
</template>
112112
</v-tooltip>
113113
</template>
@@ -141,6 +141,7 @@ import { VCard, VTextField, VBtn, VIcon, VDataTable, VTooltip, VChip } from 'vue
141141
import { useAppStore } from '@/store/app';
142142
import { sizeToBase10String } from '@/utils/memory';
143143
import { DataTableHeader, SortItem } from '@/types/common';
144+
import { UserAccount } from '@/api/client.gen';
144145
145146
import ProjectActionsMenu from '@/components/ProjectActionsMenu.vue';
146147
@@ -164,6 +165,7 @@ type ProjectTableItem = {
164165
165166
type ProjectTableSlotProps = { item: ProjectTableItem };
166167
168+
const appStore = useAppStore();
167169
const router = useRouter();
168170
169171
const search = ref<string>('');
@@ -184,7 +186,9 @@ const headers: DataTableHeader[] = [
184186
// { title: 'Date Created', key: 'date' },
185187
];
186188
187-
const appStore = useAppStore();
189+
const props = defineProps<{
190+
account: UserAccount;
191+
}>();
188192
189193
/**
190194
* Returns the user's project usage data.
@@ -196,11 +200,11 @@ const projects = computed<ProjectTableItem[]>(() => {
196200
return {
197201
used,
198202
limit,
199-
percent: used !== null ? Math.round(used * 100 / limit) : null,
203+
percent: used !== null && limit > 0 ? Math.round(used * 100 / limit) : 0,
200204
};
201205
}
202206
203-
const projects = appStore.state.userAccount?.projects;
207+
const projects = props.account.projects;
204208
if (!projects || !projects.length) {
205209
return [];
206210
}
@@ -221,7 +225,7 @@ async function selectProject(id: string): Promise<void> {
221225
await appStore.selectProject(id);
222226
router.push({
223227
name: ROUTES.AccountProject.name,
224-
params: { email: appStore.state.userAccount?.email, id },
228+
params: { email: props.account?.email, id },
225229
});
226230
}
227231

0 commit comments

Comments
 (0)