Continue frontend building
This commit is contained in:
194
packages/sshecret-frontend/src/views/secrets/SecretTreeList.vue
Normal file
194
packages/sshecret-frontend/src/views/secrets/SecretTreeList.vue
Normal file
@ -0,0 +1,194 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full min-h-0">
|
||||
<div class="tree-header mb-2 grid grid-cols-2 place-content-between">
|
||||
<h1 class="text-lg font-semibold text-gray-900 dark:text-white">Secrets</h1>
|
||||
<div class="flex">
|
||||
<div class="flex w-full justify-end">
|
||||
<sl-dropdown>
|
||||
<sl-icon-button slot="trigger" name="plus-square" label="Add Secret"></sl-icon-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item @click="createSecretDrawer = true">Create secret</sl-menu-item>
|
||||
<sl-menu-item @click="createGroupDrawer = true">
|
||||
<span v-if="currentPath">Create subgroup</span>
|
||||
<span v-else>Create group</span>
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-full">
|
||||
<!-- The search would have gone here... -->
|
||||
|
||||
</div>
|
||||
<div id="secret-tree-items" class="flex flex-col h-full min-h-0 col-span-full">
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<sl-tree class="w-full" @sl-selection-change="itemSelected" v-if="treeState.secretGroups">
|
||||
<template v-if="ungrouped">
|
||||
<SecretGroupTreeItem path="ungrouped" name="Ungrouped" groupPath="ungrouped">
|
||||
<template v-for="entry in ungrouped">
|
||||
<SecretGroupTreeEntry :name="entry.name" groupPath="ungrouped" />
|
||||
</template>
|
||||
</SecretGroupTreeItem>
|
||||
</template>
|
||||
<template v-if="secretGroups">
|
||||
<SecretGroup v-for="group in secretGroups" :group="group" />
|
||||
</template>
|
||||
</sl-tree>
|
||||
</div>
|
||||
<!-- pagination would go here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Drawer label="Create Group" :open="createGroupDrawer" @hide="createGroupDrawer = false">
|
||||
<AddGroup
|
||||
:parent="currentPath"
|
||||
@submit="createGroup"
|
||||
@cancel="cancelCreateGroup"
|
||||
:key="drawerKey"
|
||||
/>
|
||||
</Drawer>
|
||||
<Drawer label="Create Secret" :open="createSecretDrawer" @hide="createSecretDrawer = false">
|
||||
<SecretForm
|
||||
:key="createDrawerKey"
|
||||
:group="createSecretParent"
|
||||
@submit="createSecret"
|
||||
@cancel="createSecretDrawer = false"
|
||||
/>
|
||||
</Drawer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type { SshecretObject } from '@/api/types'
|
||||
import type { SecretCreate } from '@/client'
|
||||
import { computed, ref, reactive, onMounted, watch } from 'vue'
|
||||
import { useTreeState } from '@/store/useTreeState'
|
||||
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||
import { SshecretAdmin } from '@/client'
|
||||
import { SshecretObjectType } from '@/api/types'
|
||||
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'
|
||||
|
||||
const treeState = useTreeState()
|
||||
const alerts = useAlertsStore()
|
||||
|
||||
const ungrouped = computed(() => treeState.secretGroups.ungrouped)
|
||||
const secretGroups = computed(() => treeState.secretGroups.groups)
|
||||
|
||||
const groupSelected = computed(() => {
|
||||
if (!treeState.selected) {
|
||||
return false
|
||||
}
|
||||
if (treesState.selected.objectType === SshecretObject.SecretGroup) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
const drawerKey = ref(0)
|
||||
const createDrawerKey = ref(0)
|
||||
const createGroupDrawer = ref<boolean>(false)
|
||||
const createSecretDrawer = ref<boolean>(false)
|
||||
|
||||
function cancelCreateGroup() {
|
||||
createGroupDrawer.value = false
|
||||
drawerKey.value += 1
|
||||
}
|
||||
|
||||
const currentPath = computed(() => {
|
||||
if (treeState.selected && treeState.selected.objectType === SshecretObjectType.SecretGroup) {
|
||||
return treeState.selected.id
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const createSecretParent = computed(() => {
|
||||
if (treeState.selected && treeState.selected.objectType === SshecretObjectType.SecretGroup) {
|
||||
return treeState.selected.id
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
async function loadGroups() {
|
||||
await treeState.getSecretGroups()
|
||||
}
|
||||
|
||||
const drawerKeyName = computed(() => `${currentPath.value}_${drawerKey.value}`)
|
||||
|
||||
async function itemSelected(event: Event) {
|
||||
if (event.detail.selection.length == 0) {
|
||||
treeState.unselect()
|
||||
} else {
|
||||
const el = event.detail.selection[0] as HTMLElement
|
||||
const childType = el.dataset.type
|
||||
if (childType === 'secret') {
|
||||
const secretName = el.dataset.name
|
||||
treeState.selectSecret(secretName, null)
|
||||
} else if (childType === 'group') {
|
||||
const groupPath = el.dataset.groupPath
|
||||
if (groupPath === 'ungrouped') {
|
||||
treeState.unselect()
|
||||
} else {
|
||||
treeState.selectGroup(groupPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
await loadGroups()
|
||||
} else {
|
||||
console.error(response)
|
||||
alerts.showAlert('Group creation failed', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
async function createSecret(secretCreate: SecretCreate) {
|
||||
console.log('Creating secret')
|
||||
const response = await SshecretAdmin.addSecretApiV1SecretsPost({
|
||||
body: secretCreate,
|
||||
})
|
||||
if (response.status == 200) {
|
||||
alerts.showAlert('Secret created', 'success')
|
||||
// We can close the drawer now.
|
||||
createSecretDrawer.value = false
|
||||
createDrawerKey.value += 1
|
||||
|
||||
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)
|
||||
alerts.showAlert('Secret creation failed', 'error')
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => treeState.secretGroupRevision,
|
||||
() => {
|
||||
treeState.getSecretGroups()
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(loadGroups)
|
||||
</script>
|
||||
Reference in New Issue
Block a user