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

Skip to content

Commit 10a3f04

Browse files
satellite/admin-ui: use path routing for navigation
This change makes it so that navigation to users and projects are done via path parameters. Issue: #7601 Change-Id: I91ae46065f36c85369b107b98e74dfed3cbf20c2
1 parent c2540d3 commit 10a3f04

File tree

9 files changed

+115
-43
lines changed

9 files changed

+115
-43
lines changed

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,27 @@
22
// See LICENSE for copying information.
33

44
<template>
5-
<template v-if="appStore.state.settings">
5+
<div
6+
v-if="!appStore.state.settings"
7+
class="d-flex justify-center align-center align-items-center"
8+
style="height: 100vh;"
9+
>
10+
<v-skeleton-loader
11+
class="mx-auto"
12+
width="300"
13+
height="200"
14+
type="card"
15+
/>
16+
</div>
17+
<template v-else>
618
<router-view />
719
<notifications />
820
</template>
921
</template>
1022

1123
<script setup lang="ts">
1224
import { onMounted } from 'vue';
25+
import { VSkeletonLoader } from 'vuetify/components';
1326
1427
import { useAppStore } from '@/store/app';
1528
import { useNotificationsStore } from '@/store/notifications';
@@ -21,15 +34,12 @@ const notify = useNotificationsStore();
2134
2235
onMounted(async () => {
2336
try {
24-
await appStore.getPlacements();
37+
await Promise.all([
38+
appStore.getSettings(),
39+
appStore.getPlacements(),
40+
]);
2541
} catch (error) {
26-
notify.notifyError(`Failed to get placements. ${error.message}`);
27-
}
28-
29-
try {
30-
await appStore.getSettings();
31-
} catch (error) {
32-
notify.notifyError(`Failed to get settings. ${error.message}`);
42+
notify.notifyError(`Failed to initialise app. ${error.message}`);
3343
}
3444
});
3545
</script>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ const projects = computed<ProjectTableItem[]>(() => {
219219
*/
220220
async function selectProject(id: string): Promise<void> {
221221
await appStore.selectProject(id);
222-
router.push('/project-details');
222+
router.push(`${router.currentRoute.value.path}/projects/${id}`);
223223
}
224224
225225
function getPercentColor(percent: number) {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (C) 2025 Storj Labs, Inc.
2+
// See LICENSE for copying information.
3+
4+
import { ref } from 'vue';
5+
6+
export function useLoading() {
7+
const isLoading = ref<boolean>(false);
8+
9+
async function withLoading(callback): Promise<void> {
10+
if (isLoading.value) return;
11+
12+
isLoading.value = true;
13+
14+
await callback();
15+
16+
isLoading.value = false;
17+
}
18+
19+
return {
20+
isLoading,
21+
withLoading,
22+
};
23+
}

satellite/admin/back-office/ui/src/plugins/webfontloader.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

satellite/admin/back-office/ui/src/router/index.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,34 @@ const routes = [
3131
},
3232
{
3333
path: '/accounts',
34-
name: 'Accounts',
35-
component: () => import(/* webpackChunkName: "Users" */ '@/views/Accounts.vue'),
34+
children: [
35+
{
36+
path: '',
37+
name: 'Accounts',
38+
component: () => import(/* webpackChunkName: "Users" */ '@/views/Accounts.vue'),
39+
},
40+
{
41+
path: ':email',
42+
children: [
43+
{
44+
path: '',
45+
name: 'Account Details',
46+
component: () => import(/* webpackChunkName: "Users" */ '@/views/AccountDetails.vue'),
47+
},
48+
{
49+
path: 'projects/:id',
50+
name: 'User Project Details',
51+
component: () => import(/* webpackChunkName: "Users" */ '@/views/ProjectDetails.vue'),
52+
},
53+
],
54+
},
55+
],
3656
},
3757
{
3858
path: '/account-search',
3959
name: 'Search Account',
4060
component: () => import(/* webpackChunkName: "Users" */ '@/views/AccountSearch.vue'),
4161
},
42-
{
43-
path: '/account-details',
44-
name: 'Account Details',
45-
component: () => import(/* webpackChunkName: "AccountDetails" */ '@/views/AccountDetails.vue'),
46-
},
4762
{
4863
path: '/projects',
4964
name: 'Projects',

satellite/admin/back-office/ui/src/store/app.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,16 @@ export const useAppStore = defineStore('app', () => {
2121
const projectApi = new ProjectManagementHttpApiV1();
2222
const settingsApi = new SettingsHttpApiV1();
2323

24-
async function getUserByEmail(email: string): Promise<void> {
24+
async function getUserByEmail(email: string): Promise<UserAccount> {
2525
state.userAccount = await userApi.getUserByEmail(email);
26+
27+
return state.userAccount;
28+
}
29+
30+
async function getProject(id: string): Promise<Project> {
31+
state.selectedProject = await projectApi.getProject(id);
32+
33+
return state.selectedProject;
2634
}
2735

2836
function clearUser(): void {
@@ -76,6 +84,7 @@ export const useAppStore = defineStore('app', () => {
7684
return {
7785
state,
7886
getUserByEmail,
87+
getProject,
7988
clearUser,
8089
getPlacements,
8190
getPlacementText,

satellite/admin/back-office/ui/src/views/AccountDetails.vue

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// See LICENSE for copying information.
33

44
<template>
5-
<v-container>
5+
<v-container v-if="appStore.state.userAccount">
66
<v-row>
77
<v-col cols="12" md="8">
88
<PageTitleComponent title="Account Details" />
@@ -266,7 +266,19 @@ const usageCacheError = computed<boolean>(() => {
266266
);
267267
});
268268
269-
onBeforeMount(() => !userAccount.value && router.push('/accounts'));
269+
onBeforeMount(async () => {
270+
if (appStore.state.userAccount !== null) {
271+
return;
272+
}
273+
274+
try {
275+
const email = router.currentRoute.value.params.email as string;
276+
await appStore.getUserByEmail(email);
277+
} catch {
278+
router.push('/account-search');
279+
}
280+
});
281+
270282
onUnmounted(() => {
271283
if (appStore.state.selectedProject === null) {
272284
appStore.clearUser();

satellite/admin/back-office/ui/src/views/AccountSearch.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ async function goToUser(): Promise<void> {
9090
const retryDelay = 1000;
9191
for (let attempt = 0; attempt < maxAttempts; attempt++) {
9292
try {
93-
await appStore.getUserByEmail(email.value);
94-
router.push(`/account-details`);
93+
const user = await appStore.getUserByEmail(email.value);
94+
router.push(`/accounts/${user.email}`);
9595
isLoading.value = false;
9696
return;
9797
} catch (error) {

satellite/admin/back-office/ui/src/views/ProjectDetails.vue

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
// See LICENSE for copying information.
33

44
<template>
5-
<v-container>
5+
<v-container v-if="project && userAccount">
66
<v-row>
77
<v-col cols="12" md="8">
88
<PageTitleComponent title="Project Details" />
99

10-
<v-chip variant="outlined" color="default" class="mr-2 mb-2 mb-md-0 pr-4" router-link to="/account-details">
10+
<v-chip variant="outlined" color="default" class="mr-2 mb-2 mb-md-0 pr-4" router-link :to="`/accounts/${userAccount.email}`">
1111
<v-tooltip activator="parent" location="top">
1212
Go to account
1313
</v-tooltip>
@@ -171,7 +171,7 @@
171171
</template>
172172

173173
<script setup lang="ts">
174-
import { computed } from 'vue';
174+
import { computed, onMounted } from 'vue';
175175
import {
176176
VAlert,
177177
VContainer,
@@ -185,6 +185,7 @@ import {
185185
VCardText,
186186
VDivider,
187187
} from 'vuetify/components';
188+
import { useRouter } from 'vue-router';
188189
189190
import { FeatureFlags, Project, UserAccount } from '@/api/client.gen';
190191
import { useAppStore } from '@/store/app';
@@ -201,6 +202,8 @@ import ProjectLimitsDialog from '@/components/ProjectLimitsDialog.vue';
201202
import ProjectInformationDialog from '@/components/ProjectInformationDialog.vue';
202203
203204
const appStore = useAppStore();
205+
const router = useRouter();
206+
204207
const featureFlags = appStore.state.settings.admin.features as FeatureFlags;
205208
206209
const userAccount = computed<UserAccount>(() => appStore.state.userAccount as UserAccount);
@@ -216,4 +219,22 @@ const placementText = computed<string>(() => {
216219
const usageCacheError = computed<boolean>(() => {
217220
return project.value.storageUsed === null || project.value.segmentUsed === null;
218221
});
222+
223+
onMounted(async () => {
224+
if (project.value) {
225+
return;
226+
}
227+
const projectID = router.currentRoute.value.params.id as string;
228+
const userEmail = router.currentRoute.value.params.email as string;
229+
230+
try {
231+
await Promise.all([
232+
appStore.getProject(projectID),
233+
appStore.getUserByEmail(userEmail),
234+
]);
235+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
236+
} catch (error) {
237+
router.push('/account-search');
238+
}
239+
});
219240
</script>

0 commit comments

Comments
 (0)