Implement routes and transitions
This commit is contained in:
@ -1,93 +1,6 @@
|
||||
<template>
|
||||
<MasterDetail>
|
||||
<template #master>
|
||||
<sl-tab-group
|
||||
id="sideTabs"
|
||||
class="flex flex-col flex-1 h-full overflow-hidden master-pane-tabs"
|
||||
@sl-tab-show="tabSelected($event)"
|
||||
>
|
||||
<sl-tab slot="nav" panel="clients">Clients</sl-tab>
|
||||
<sl-tab slot="nav" panel="secrets">Secrets</sl-tab>
|
||||
<sl-tab slot="nav" panel="audit">Audit</sl-tab>
|
||||
<sl-tab-panel name="clients">
|
||||
<ClientTreeList />
|
||||
</sl-tab-panel>
|
||||
<sl-tab-panel name="secrets">
|
||||
<SecretTreeList />
|
||||
</sl-tab-panel>
|
||||
<sl-tab-panel name="audit">
|
||||
<AuditFilters />
|
||||
</sl-tab-panel>
|
||||
</sl-tab-group>
|
||||
</template>
|
||||
<template #detail v-if="showAudit">
|
||||
<AuditView />
|
||||
</template>
|
||||
<template #detail v-else>
|
||||
<template v-if="treeState.selected">
|
||||
<ClientDetailView
|
||||
v-if="treeState.selected.objectType === SshecretObjectType.Client"
|
||||
:clientId="treeState.selected.id"
|
||||
:key="treeState.selected.id"
|
||||
/>
|
||||
<SecretDetailView
|
||||
v-else-if="treeState.selected.objectType === SshecretObjectType.ClientSecret"
|
||||
:secretName="treeState.selected.id"
|
||||
:parentId="null"
|
||||
:key="treeState.selected.id"
|
||||
/>
|
||||
<SecretGroupDetailView
|
||||
v-else-if="
|
||||
treeState.selected.objectType === SshecretObjectType.SecretGroup &&
|
||||
treeState.selected.id != 'ungrouped'
|
||||
"
|
||||
:groupPath="treeState.selected.id"
|
||||
:key="treeState.selected.id"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</MasterDetail>
|
||||
<MasterDetailWorkspace />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import AuditView from '@/views/audit/AuditView.vue'
|
||||
import MasterDetail from '@/views/layout/MasterDetail.vue'
|
||||
import ClientTreeList from '@/views/clients/ClientTreeList.vue'
|
||||
import SecretTreeList from '@/views/secrets/SecretTreeList.vue'
|
||||
import ClientDetailView from '@/views/clients/ClientDetailView.vue'
|
||||
import SecretDetailView from '@/views/secrets/SecretDetailView.vue'
|
||||
import SecretGroupDetailView from '@/views/secrets/SecretGroupDetailView.vue'
|
||||
|
||||
import AuditFilters from '@/components/audit/AuditFilters.vue'
|
||||
import { SshecretObjectType } from '@/api/types'
|
||||
import { useAuditFilterState } from '@/store/useAuditFilterState'
|
||||
import { useTreeState } from '@/store/useTreeState'
|
||||
|
||||
const treeState = useTreeState()
|
||||
|
||||
const auditFilterState = useAuditFilterState()
|
||||
|
||||
const showAudit = ref<{ boolean }>()
|
||||
|
||||
function tabSelected(tab) {
|
||||
const tabName = tab.detail.name
|
||||
if (tabName == 'audit') {
|
||||
console.log('Showing audit')
|
||||
treeState.showAudit = true
|
||||
showAudit.value = true
|
||||
} else {
|
||||
treeState.showAudit = false
|
||||
showAudit.value = false
|
||||
}
|
||||
}
|
||||
import MasterDetailWorkspace from '@/components/common/MasterDetailWorkspace.vue'
|
||||
</script>
|
||||
|
||||
<style>
|
||||
sl-tab-group.master-pane-tabs::part(base),
|
||||
sl-tab-group.master-pane-tabs::part(body),
|
||||
sl-tab-group.master-pane-tabs sl-tab-panel::part(base),
|
||||
sl-tab-group.master-pane-tabs sl-tab-panel::part(body),
|
||||
sl-tab-group.master-pane-tabs sl-tab-panel {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
29
packages/sshecret-frontend/src/views/audit/AuditPage.vue
Normal file
29
packages/sshecret-frontend/src/views/audit/AuditPage.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<MasterDetail>
|
||||
<template #master>
|
||||
<MasterTabs selectedTab="audit" @change="tabSelected" />
|
||||
</template>
|
||||
<template #detail>
|
||||
<AuditView />
|
||||
</template>
|
||||
</MasterDetail>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import AuditView from '@/views/audit/AuditView.vue'
|
||||
import MasterDetail from '@/views/layout/MasterDetail.vue'
|
||||
import MasterTabs from '@/components/common/MasterTabs.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { RouterView } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
function tabSelected(tabName: string) {
|
||||
if (tabName !== 'audit') {
|
||||
router.push({ name: tabName })
|
||||
}
|
||||
}
|
||||
|
||||
const routeKey = computed(() => route.name + '-' + (route.params.id ?? 'root'))
|
||||
</script>
|
||||
@ -2,10 +2,14 @@
|
||||
<template v-if="loaded">
|
||||
<AuditTable :auditFilter="auditFilter" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<AuditSkeleton />
|
||||
</template>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import AuditTable from '@/components/audit/AuditTable.vue'
|
||||
import AuditSkeleton from '@/components/audit/AuditSkeleton.vue'
|
||||
import type { AuditFilter } from '@/api/types'
|
||||
import type { GetAuditLogApiV1AuditGetData } from '@/client'
|
||||
import { useAuditFilterState } from '@/store/useAuditFilterState'
|
||||
@ -13,10 +17,10 @@ const auditFilterState = useAuditFilterState()
|
||||
const auditFilter = ref<GetAuditLogApiV1AuditGetData['query']>({})
|
||||
|
||||
watch(auditFilterState, () => (auditFilter.value = auditFilterState.getFilter))
|
||||
const loaded = ref<{ boolean }>()
|
||||
const loaded = ref<{ boolean }>(false)
|
||||
|
||||
onMounted(() => {
|
||||
loaded.value = true
|
||||
auditFilter.value = auditFilterState.getFilter
|
||||
loaded.value = true
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<ClientDetailView :id="clientId" :parentId="parentId" @clientDeleted="onClientDelete" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { toRef } from 'vue'
|
||||
import ClientDetailView from '@/views/clients/ClientDetailView.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useTreeState } from '@/store/useTreeState'
|
||||
|
||||
const props = defineProps<{ id: string | null; parentId: string | null }>()
|
||||
const router = useRouter()
|
||||
const clientId = toRef(() => props.id)
|
||||
const parentId = toRef(() => props.parentId)
|
||||
|
||||
const treeState = useTreeState()
|
||||
|
||||
async function onClientDelete(id: string) {
|
||||
// React when a client is deleted
|
||||
|
||||
console.log('Client deleted')
|
||||
await treeState.loadClients()
|
||||
router.push({ name: 'clients' })
|
||||
}
|
||||
</script>
|
||||
@ -1,44 +1,54 @@
|
||||
<template>
|
||||
<ClientDetail :client="client" @update="updateClient" @deleted="deleteClient" v-if="client" />
|
||||
<ClientDetail
|
||||
:client="client"
|
||||
@update="updateClient"
|
||||
@deleted="deleteClient"
|
||||
v-if="client"
|
||||
:key="clientId"
|
||||
/>
|
||||
<ClientSkeleton v-else />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
import { ref, toRef, watch, onMounted } from 'vue'
|
||||
import ClientSkeleton from '@/components/clients/ClientSkeleton.vue'
|
||||
import ClientDetail from '@/components/clients/ClientDetail.vue'
|
||||
import type { ClientCreate } from '@/client'
|
||||
import { idKey } from '@/api/paths'
|
||||
import { SshecretAdmin } from '@/client'
|
||||
import { useTreeState } from '@/store/useTreeState'
|
||||
|
||||
const props = defineProps<{ clientId: string | null }>()
|
||||
const props = defineProps<{ id: string | null; parentId: string | null }>()
|
||||
|
||||
const clientId = toRef(() => props.id)
|
||||
|
||||
const client = ref<Client>()
|
||||
|
||||
const treeState = useTreeState()
|
||||
|
||||
const emit = defineEmits<{ (e: 'clientDeleted', data: string): void }>()
|
||||
|
||||
async function loadClient() {
|
||||
if (!props.clientId) return
|
||||
client.value = await treeState.getClient()
|
||||
console.log('loadClient called: ', props.id)
|
||||
if (!props.id) return
|
||||
client.value = await treeState.getClient(props.id)
|
||||
}
|
||||
|
||||
async function deleteClient(clientId: string) {
|
||||
console.log(`Delete ${localClient.value.id}`)
|
||||
async function deleteClient(deleteId: string) {
|
||||
const response = await SshecretAdmin.deleteClientApiV1ClientsIdDelete({
|
||||
path: { id: clientId },
|
||||
path: { id: idKey(deleteId) },
|
||||
})
|
||||
if (response.status !== 200) {
|
||||
console.error(response)
|
||||
return
|
||||
}
|
||||
|
||||
emit('clientDeleted', clientId)
|
||||
props.clientId = null
|
||||
emit('clientDeleted', deleteId)
|
||||
}
|
||||
|
||||
async function updateClient(updated: ClientCreate) {
|
||||
const response = await SshecretAdmin.updateClientApiV1ClientsIdPut({
|
||||
path: { id: localClient.value.id },
|
||||
path: { id: idKey(localClient.value.id) },
|
||||
body: data,
|
||||
})
|
||||
client.value = response.data
|
||||
@ -47,7 +57,7 @@ async function updateClient(updated: ClientCreate) {
|
||||
onMounted(loadClient)
|
||||
|
||||
watch(
|
||||
() => props.client_id,
|
||||
() => props.id,
|
||||
() => loadClient(),
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
29
packages/sshecret-frontend/src/views/clients/ClientPage.vue
Normal file
29
packages/sshecret-frontend/src/views/clients/ClientPage.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<MasterDetail>
|
||||
<template #master>
|
||||
<MasterTabs selectedTab="clients" @change="tabSelected" />
|
||||
</template>
|
||||
<template #detail>
|
||||
<RouterView :key="routeKey" />
|
||||
</template>
|
||||
</MasterDetail>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import MasterDetail from '@/views/layout/MasterDetail.vue'
|
||||
import MasterTabs from '@/components/common/MasterTabs.vue'
|
||||
import ClientDetailView from '@/views/clients/ClientDetailView.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { RouterView } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
function tabSelected(tabName: string) {
|
||||
if (tabName !== 'clients') {
|
||||
router.push({ name: tabName })
|
||||
}
|
||||
}
|
||||
|
||||
const routeKey = computed(() => route.name + '-' + (route.params.id ?? 'root'))
|
||||
</script>
|
||||
@ -44,6 +44,11 @@
|
||||
</ClientTreeItem>
|
||||
</template>
|
||||
</sl-tree>
|
||||
<sl-tree class="w-full" v-else>
|
||||
<template v-for="n in 20">
|
||||
<TreeItemSkeleton />
|
||||
</template>
|
||||
</sl-tree>
|
||||
</div>
|
||||
<div
|
||||
class="shrink-0 mt-4 pt-2 border-t border-gray-100 dark:border-gray-700 bg-white dark:bg-gray-800"
|
||||
@ -88,7 +93,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, reactive, onMounted, watch } from 'vue'
|
||||
import { computed, ref, reactive, toRef, onMounted, watch, nextTick } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
import { usePagination } from '@/composables/usePagination'
|
||||
@ -98,11 +103,13 @@ import { SshecretAdmin } from '@/client/sdk.gen'
|
||||
import type { Client, ClientCreate } from '@/client/types.gen'
|
||||
|
||||
import { useTreeState } from '@/store/useTreeState'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
import ClientTreeItem from '@/components/clients/ClientTreeItem.vue'
|
||||
import ClientSecretTreeItem from '@/components/clients/ClientSecretTreeItem.vue'
|
||||
import ClientForm from '@/components/clients/ClientForm.vue'
|
||||
import PageNumbers from '@/components/common/PageNumbers.vue'
|
||||
import TreeItemSkeleton from '@/components/common/TreeItemSkeleton.vue'
|
||||
|
||||
import { useDebounce } from '@/composables/useDebounce'
|
||||
const treeState = useTreeState()
|
||||
@ -117,7 +124,15 @@ const selectedSecret = ref<string | null>(null)
|
||||
const createFormKey = ref<number>(0)
|
||||
const createDrawerOpen = ref<boolean>(false)
|
||||
|
||||
const clientQuery = ref('')
|
||||
const props = defineProps({
|
||||
loadClient: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const router = useRouter()
|
||||
|
||||
const clientQuery = toRef(() => props.loadClient)
|
||||
|
||||
const debouncedQuery = useDebounce(clientQuery, 300)
|
||||
|
||||
@ -134,49 +149,43 @@ async function loadClients() {
|
||||
|
||||
function updateClient(updated: Client) {
|
||||
const index = clients.value.findIndex((c) => c.name === updated.name)
|
||||
console.log(`UpdateClient fired: ${updated.name} => ${index}`)
|
||||
if (index >= 0) {
|
||||
clients.value[index] = updated
|
||||
}
|
||||
}
|
||||
|
||||
function itemSelected(event: Event) {
|
||||
if (event.detail.selection.length == 0) {
|
||||
treeState.unselect()
|
||||
} else {
|
||||
if (event.detail.selection) {
|
||||
const el = event.detail.selection[0] as HTMLElement
|
||||
const childType = el.dataset.type
|
||||
if (childType === 'client') {
|
||||
const clientId = el.dataset.clientId
|
||||
treeState.selectClient(clientId)
|
||||
} else if (childType == 'secret') {
|
||||
const secretName = el.dataset.name
|
||||
router.push({ name: 'Client', params: { id: el.dataset.clientId } })
|
||||
} else {
|
||||
const secretId = el.dataset.name
|
||||
const parentId = el.dataset.parentId
|
||||
treeState.selectSecret(secretName, parentId)
|
||||
console.log(el.dataset)
|
||||
router.push({
|
||||
name: 'ClientSecret',
|
||||
params: { parentId: el.dataset.parentId, id: el.dataset.name },
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function createClient(data: ClientCreate) {
|
||||
const response = await SshecretAdmin.createClientApiV1ClientsPost({ body: data })
|
||||
console.log(response.data)
|
||||
clients.value.unshift(response.data)
|
||||
totalClients.value += 1
|
||||
createDrawerOpen.value = false
|
||||
createFormKey.value += 1
|
||||
treeState.value.selected = true
|
||||
treeState.value.item_type = 'secret'
|
||||
treeState.value.client = response.data
|
||||
treeState.selectClient(response.data.id)
|
||||
router.push({ name: 'Client', params: { id: response.data.id } })
|
||||
}
|
||||
|
||||
async function clientDeleted(id: string) {
|
||||
const index = clients.value.findIndex((c) => c.id === id)
|
||||
console.log(`Client Deleted event received: ID: ${id} => ${index}`)
|
||||
if (index >= 0) {
|
||||
clients.value.splice(index, 1)
|
||||
treeState.value.selected = false
|
||||
treeState.value.item_type = null
|
||||
treeState.value.client = null
|
||||
treeState.unselect()
|
||||
await loadClients()
|
||||
}
|
||||
}
|
||||
@ -196,7 +205,6 @@ async function clearSearch() {
|
||||
|
||||
// Watch the search query
|
||||
watch(debouncedQuery, async () => {
|
||||
console.log('Handling search event.')
|
||||
await handleSearchEvent()
|
||||
})
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
<section id="detail-pane" class="flex-1 flex overflow-y-auto bg-white p-4 dark:bg-gray-800">
|
||||
<div class="flex flex-col w-full">
|
||||
<slot name="detail">
|
||||
<p class="p-4 text-gray-500 dark:text-gray-200">Select an item to view details</p>
|
||||
<GenericDetail />
|
||||
</slot>
|
||||
</div>
|
||||
</section>
|
||||
@ -38,6 +38,7 @@
|
||||
import { ref } from 'vue'
|
||||
import '@shoelace-style/shoelace/dist/components/icon/icon.js'
|
||||
import Navbar from '@/components/layout/Navbar.vue'
|
||||
import GenericDetail from '@/components/common/GenericDetail.vue'
|
||||
|
||||
const masterHidden = ref(true)
|
||||
</script>
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<SecretDetail
|
||||
:secret="secret"
|
||||
@update="updateSecretValue"
|
||||
@delete="deleteSecret"
|
||||
@addClient="addSecretToClient"
|
||||
@removeClient="removeClientSecret"
|
||||
v-if="secret"
|
||||
/>
|
||||
<SecretSkeleton v-else />
|
||||
<div>
|
||||
<SecretDetail
|
||||
:secret="secret"
|
||||
@update="updateSecretValue"
|
||||
@delete="deleteSecret"
|
||||
@addClient="addSecretToClient"
|
||||
@removeClient="removeClientSecret"
|
||||
v-if="secret"
|
||||
/>
|
||||
<SecretSkeleton v-else />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
@ -18,21 +20,21 @@ import { useTreeState } from '@/store/useTreeState'
|
||||
import type { SecretView } from '@/client/types.gen.ts'
|
||||
import { SshecretAdmin } from '@/client'
|
||||
|
||||
const props = defineProps<{ secretName: string | null; parentId: string | null }>()
|
||||
const props = defineProps<{ id: string | null; parentId: string | null }>()
|
||||
const secret = ref<SecretView>()
|
||||
|
||||
const treeState = useTreeState()
|
||||
|
||||
async function loadSecret() {
|
||||
if (!props.secretName) return
|
||||
secret.value = await treeState.getSecret(props.secretName)
|
||||
if (!props.id) return
|
||||
secret.value = await treeState.getSecret(props.id)
|
||||
}
|
||||
|
||||
async function updateSecretValue(value: string) {
|
||||
// Update a secret value
|
||||
await SshecretAdmin.updateSecretApiV1SecretsNamePut({
|
||||
path: {
|
||||
name: props.secretName,
|
||||
name: props.id,
|
||||
},
|
||||
body: {
|
||||
value: value,
|
||||
@ -46,8 +48,8 @@ async function updateSecretValue(value: string) {
|
||||
|
||||
async function deleteSecret(clients: string[]) {
|
||||
// Delete the whole secret
|
||||
if (props.secretName) {
|
||||
await SshecretAdmin.deleteSecretApiV1SecretsNameDelete({ path: { name: props.secretName } })
|
||||
if (props.id) {
|
||||
await SshecretAdmin.deleteSecretApiV1SecretsNameDelete({ path: { name: props.id } })
|
||||
for (const clientId in clients) {
|
||||
await treeState.refreshClient(clientId)
|
||||
}
|
||||
@ -55,12 +57,11 @@ async function deleteSecret(clients: string[]) {
|
||||
}
|
||||
|
||||
async function addSecretToClient(clientId: string) {
|
||||
if (props.secretName) {
|
||||
console.log('Add Secret to client', props.secretName, clientId)
|
||||
if (props.id) {
|
||||
await SshecretAdmin.addSecretToClientApiV1ClientsIdSecretsSecretNamePut({
|
||||
path: {
|
||||
id: clientId,
|
||||
secret_name: props.secretName,
|
||||
secret_name: props.id,
|
||||
},
|
||||
})
|
||||
await treeState.refreshClient(clientId)
|
||||
@ -69,11 +70,11 @@ async function addSecretToClient(clientId: string) {
|
||||
}
|
||||
|
||||
async function removeClientSecret(clientId: string) {
|
||||
if (props.secretName) {
|
||||
if (props.id) {
|
||||
await SshecretAdmin.deleteSecretFromClientApiV1ClientsIdSecretsSecretNameDelete({
|
||||
path: {
|
||||
id: clientId,
|
||||
secret_name: props.secretName,
|
||||
secret_name: props.id,
|
||||
},
|
||||
})
|
||||
await treeState.refreshClient(clientId)
|
||||
@ -83,7 +84,7 @@ async function removeClientSecret(clientId: string) {
|
||||
onMounted(loadSecret)
|
||||
|
||||
watch(
|
||||
() => props.secretName,
|
||||
() => props.id,
|
||||
() => loadSecret(),
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<GroupDetail :group="group" v-if="group" />
|
||||
<ClientSkeleton v-else />
|
||||
<div>
|
||||
<Transition name="fade" :css="false">
|
||||
<div>
|
||||
<GroupDetail :group="group" v-if="group" />
|
||||
<ClientSkeleton v-else />
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, onMounted } from 'vue'
|
||||
|
||||
32
packages/sshecret-frontend/src/views/secrets/SecretPage.vue
Normal file
32
packages/sshecret-frontend/src/views/secrets/SecretPage.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<MasterDetail>
|
||||
<template #master>
|
||||
<MasterTabs selectedTab="secrets" @change="tabSelected" />
|
||||
</template>
|
||||
<template #detail>
|
||||
<RouterView v-slot="{ Component, route }">
|
||||
<transition name="fade" :css="false">
|
||||
<component :is="Component" :key="route.path" />
|
||||
</transition>
|
||||
</RouterView>
|
||||
</template>
|
||||
</MasterDetail>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import MasterDetail from '@/views/layout/MasterDetail.vue'
|
||||
import MasterTabs from '@/components/common/MasterTabs.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { RouterView } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
function tabSelected(tabName: string) {
|
||||
if (tabName !== 'secrets') {
|
||||
router.push({ name: tabName })
|
||||
}
|
||||
}
|
||||
|
||||
const routeKey = computed(() => route.name + '-' + (route.params.id ?? 'root'))
|
||||
</script>
|
||||
@ -34,6 +34,11 @@
|
||||
<SecretGroup v-for="group in secretGroups" :group="group" />
|
||||
</template>
|
||||
</sl-tree>
|
||||
<sl-tree v-else>
|
||||
<template v-for="n in 10">
|
||||
<TreeItemSkeleton />
|
||||
</template>
|
||||
</sl-tree>
|
||||
</div>
|
||||
<!-- pagination would go here -->
|
||||
</div>
|
||||
@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user