From 5ac4c987d32734329c11dcbd80b8e005cd39e795 Mon Sep 17 00:00:00 2001 From: Allan Eising Date: Mon, 14 Jul 2025 12:08:09 +0200 Subject: [PATCH] Implement routes and transitions --- packages/sshecret-frontend/src/api/paths.ts | 23 ++ packages/sshecret-frontend/src/api/types.ts | 6 + .../src/components/audit/AuditSkeleton.vue | 108 ++++++ .../src/components/audit/AuditTable.vue | 355 +++++++++--------- .../clients/ClientSecretTreeItem.vue | 4 +- .../src/components/clients/ClientSkeleton.vue | 6 - .../src/components/common/DetailPage.vue | 15 + .../src/components/common/GenericDetail.vue | 3 + .../common/MasterDetailWorkspace.vue | 109 ++++++ .../src/components/common/MasterTabs.vue | 36 ++ .../components/common/TreeItemSkeleton.vue | 15 + .../src/components/secrets/SecretSkeleton.vue | 108 ++++-- packages/sshecret-frontend/src/main.ts | 2 + .../sshecret-frontend/src/router/index.ts | 59 ++- .../src/store/useTreeState.ts | 16 + .../src/views/WorkspaceView.vue | 91 +---- .../src/views/audit/AuditPage.vue | 29 ++ .../src/views/audit/AuditView.vue | 8 +- .../src/views/clients/ClientDetailPage.vue | 24 ++ .../src/views/clients/ClientDetailView.vue | 34 +- .../src/views/clients/ClientPage.vue | 29 ++ .../src/views/clients/ClientTreeList.vue | 50 +-- .../src/views/layout/MasterDetail.vue | 3 +- .../src/views/secrets/SecretDetailView.vue | 43 +-- .../views/secrets/SecretGroupDetailView.vue | 10 +- .../src/views/secrets/SecretPage.vue | 32 ++ .../src/views/secrets/SecretTreeList.vue | 18 +- 27 files changed, 860 insertions(+), 376 deletions(-) create mode 100644 packages/sshecret-frontend/src/api/paths.ts create mode 100644 packages/sshecret-frontend/src/components/audit/AuditSkeleton.vue create mode 100644 packages/sshecret-frontend/src/components/common/DetailPage.vue create mode 100644 packages/sshecret-frontend/src/components/common/GenericDetail.vue create mode 100644 packages/sshecret-frontend/src/components/common/MasterDetailWorkspace.vue create mode 100644 packages/sshecret-frontend/src/components/common/MasterTabs.vue create mode 100644 packages/sshecret-frontend/src/components/common/TreeItemSkeleton.vue create mode 100644 packages/sshecret-frontend/src/views/audit/AuditPage.vue create mode 100644 packages/sshecret-frontend/src/views/clients/ClientDetailPage.vue create mode 100644 packages/sshecret-frontend/src/views/clients/ClientPage.vue create mode 100644 packages/sshecret-frontend/src/views/secrets/SecretPage.vue diff --git a/packages/sshecret-frontend/src/api/paths.ts b/packages/sshecret-frontend/src/api/paths.ts new file mode 100644 index 0000000..d34df58 --- /dev/null +++ b/packages/sshecret-frontend/src/api/paths.ts @@ -0,0 +1,23 @@ + +/* + * Split a path like /foo/bar/baz into ['foo', 'bar', 'baz'] + */ +export function splitPath(path: string): string[] { + if (path.startsWith('/')) { + const newPath = path.substring(1) + return newPath.split("/") + } + return path.split("/") +} + +/* + * Reassemble a path array like ['foo', 'bar', 'baz'] into /foo/bar/baz + */ +export function reassemblePath(segments: string[]): string { + const elements = segments.join('/') + return '/' + elements +} + +export function idKey(id: string): string { + return 'id:' + id +} diff --git a/packages/sshecret-frontend/src/api/types.ts b/packages/sshecret-frontend/src/api/types.ts index 0715ceb..7ddf6c8 100644 --- a/packages/sshecret-frontend/src/api/types.ts +++ b/packages/sshecret-frontend/src/api/types.ts @@ -8,6 +8,7 @@ export enum SshecretObjectType { Client = "Client", ClientSecret = "ClientSecret", SecretGroup = "SecretGroup", + Audit = "Audit", // Not technically an object, but added for navigational purposes. } export type SshecretObject = { @@ -71,3 +72,8 @@ export const SUBSYSTEM = [ 'sshd', 'backend', ] as const + +export interface PageState { + activePane: 'clients' | 'secrets' | 'audit', + selectedObject?: string, +} diff --git a/packages/sshecret-frontend/src/components/audit/AuditSkeleton.vue b/packages/sshecret-frontend/src/components/audit/AuditSkeleton.vue new file mode 100644 index 0000000..3aa2795 --- /dev/null +++ b/packages/sshecret-frontend/src/components/audit/AuditSkeleton.vue @@ -0,0 +1,108 @@ + + + diff --git a/packages/sshecret-frontend/src/components/audit/AuditTable.vue b/packages/sshecret-frontend/src/components/audit/AuditTable.vue index 314bb28..d0f34a3 100644 --- a/packages/sshecret-frontend/src/components/audit/AuditTable.vue +++ b/packages/sshecret-frontend/src/components/audit/AuditTable.vue @@ -1,182 +1,190 @@ diff --git a/packages/sshecret-frontend/src/views/clients/ClientDetailPage.vue b/packages/sshecret-frontend/src/views/clients/ClientDetailPage.vue new file mode 100644 index 0000000..cb3b393 --- /dev/null +++ b/packages/sshecret-frontend/src/views/clients/ClientDetailPage.vue @@ -0,0 +1,24 @@ + + diff --git a/packages/sshecret-frontend/src/views/clients/ClientDetailView.vue b/packages/sshecret-frontend/src/views/clients/ClientDetailView.vue index a840df8..cc325ed 100644 --- a/packages/sshecret-frontend/src/views/clients/ClientDetailView.vue +++ b/packages/sshecret-frontend/src/views/clients/ClientDetailView.vue @@ -1,44 +1,54 @@ diff --git a/packages/sshecret-frontend/src/views/clients/ClientTreeList.vue b/packages/sshecret-frontend/src/views/clients/ClientTreeList.vue index 51ec41a..758f2be 100644 --- a/packages/sshecret-frontend/src/views/clients/ClientTreeList.vue +++ b/packages/sshecret-frontend/src/views/clients/ClientTreeList.vue @@ -44,6 +44,11 @@ + + +
diff --git a/packages/sshecret-frontend/src/views/secrets/SecretDetailView.vue b/packages/sshecret-frontend/src/views/secrets/SecretDetailView.vue index e18f9c4..659eb6f 100644 --- a/packages/sshecret-frontend/src/views/secrets/SecretDetailView.vue +++ b/packages/sshecret-frontend/src/views/secrets/SecretDetailView.vue @@ -1,13 +1,15 @@ diff --git a/packages/sshecret-frontend/src/views/secrets/SecretTreeList.vue b/packages/sshecret-frontend/src/views/secrets/SecretTreeList.vue index 84e3aa5..8e352a1 100644 --- a/packages/sshecret-frontend/src/views/secrets/SecretTreeList.vue +++ b/packages/sshecret-frontend/src/views/secrets/SecretTreeList.vue @@ -34,6 +34,11 @@ + + +
@@ -60,17 +65,21 @@ import type { SshecretObject } from '@/api/types' import type { SecretCreate } from '@/client' import { computed, ref, reactive, onMounted, watch } from 'vue' +import { useRouter, useRoute } from 'vue-router' import { useTreeState } from '@/store/useTreeState' import { useAlertsStore } from '@/store/useAlertsStore' import { SshecretAdmin } from '@/client' import { SshecretObjectType } from '@/api/types' +import { splitPath } from '@/api/paths' import SecretGroup from '@/components/secrets/SecretGroup.vue' import SecretGroupTreeItem from '@/components/secrets/SecretGroupTreeItem.vue' import SecretGroupTreeEntry from '@/components/secrets/SecretGroupTreeEntry.vue' import AddGroup from '@/components/secrets/AddGroup.vue' import SecretForm from '@/components/secrets/SecretForm.vue' import Drawer from '@/components/common/Drawer.vue' +import TreeItemSkeleton from '@/components/common/TreeItemSkeleton.vue' +const router = useRouter() const treeState = useTreeState() const alerts = useAlertsStore() @@ -126,12 +135,15 @@ async function itemSelected(event: Event) { if (childType === 'secret') { const secretName = el.dataset.name treeState.selectSecret(secretName, null) + router.push({ name: 'Secret', params: { id: secretName } }) } else if (childType === 'group') { const groupPath = el.dataset.groupPath if (groupPath === 'ungrouped') { treeState.unselect() } else { + const groupPathElements = splitPath(groupPath) treeState.selectGroup(groupPath) + router.push({ name: 'Group', params: { groupPath: groupPathElements } }) } } } @@ -139,14 +151,12 @@ async function itemSelected(event: Event) { async function createGroup(path: string) { // Create a group - console.log('Submit called') const response = await SshecretAdmin.addSecretGroupApiV1SecretsGroupsPost({ body: { name: path, }, }) if (response.status === 200) { - console.log('Success. Group created.') alerts.showAlert('Group created', 'success') createGroupDrawer.value = false drawerKey.value += 1 @@ -159,7 +169,6 @@ async function createGroup(path: string) { } async function createSecret(secretCreate: SecretCreate) { - console.log('Creating secret') const response = await SshecretAdmin.addSecretApiV1SecretsPost({ body: secretCreate, }) @@ -172,13 +181,12 @@ async function createSecret(secretCreate: SecretCreate) { await loadGroups() // Also update all the clients affected for (const clientId in secretCreate.clients) { - console.log('Refreshing client: ', clientId) await treeState.refreshClient(clientId) } treeState.selectSecret(secretCreate.name) } else { - console.log(response) + console.error(response) alerts.showAlert('Secret creation failed', 'error') } }