Deletions, group moves and validation
This commit is contained in:
@ -7,7 +7,7 @@ So, this is the steps I need to take.
|
|||||||
* DONE Write a typescript API client.
|
* DONE Write a typescript API client.
|
||||||
I suppose this can be rendered from OpenAPI?
|
I suppose this can be rendered from OpenAPI?
|
||||||
|
|
||||||
* Install the required libraries
|
* DONE Install the required libraries
|
||||||
+ [X] Flowbite
|
+ [X] Flowbite
|
||||||
+ [X] Shoelace
|
+ [X] Shoelace
|
||||||
+ [X] tailwind
|
+ [X] tailwind
|
||||||
@ -15,9 +15,26 @@ I suppose this can be rendered from OpenAPI?
|
|||||||
I've set up flowbite-vue here.
|
I've set up flowbite-vue here.
|
||||||
https://flowbite-vue.com/pages/getting-started
|
https://flowbite-vue.com/pages/getting-started
|
||||||
* DONE Set up base page
|
* DONE Set up base page
|
||||||
* Set up login page (basic)
|
* DONE Set up login page (basic)
|
||||||
+ [ ] Create an authentication state store
|
+ [X] Create an authentication state store
|
||||||
+ [ ] Use the rendered API to send login details, and receive tokens
|
+ [X] Use the rendered API to send login details, and receive tokens
|
||||||
+ [ ] Consider adding a refresh token thing to the API
|
+ [X] Consider adding a refresh token thing to the API
|
||||||
|
|
||||||
* Create the master/detail page
|
* DONE Create the master/detail page
|
||||||
|
|
||||||
|
* Views
|
||||||
|
** Secret View
|
||||||
|
+ [X] Add dropdown
|
||||||
|
+ [X] Implement delete
|
||||||
|
+ [X] Implement move
|
||||||
|
|
||||||
|
* Navigation
|
||||||
|
** DONE Implement hard links
|
||||||
|
+ All selections can be done to the state,
|
||||||
|
except the tab selection
|
||||||
|
|
||||||
|
* Error handling
|
||||||
|
+ [X] Check styling on sl-alert
|
||||||
|
+ [X] Ensure that its z-index is above any popups
|
||||||
|
+ [X] Refine field-based validation in ClientForm for other fields
|
||||||
|
+ [ ] Implement validation in SecretForm
|
||||||
|
|||||||
@ -1,21 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<sl-alert
|
<ShowAlerts />
|
||||||
v-for="alert in alerts.alerts"
|
|
||||||
:key="alert.id"
|
|
||||||
:variant="alert.type"
|
|
||||||
open
|
|
||||||
closable
|
|
||||||
:duration="['warning', 'error'].includes(alert.type) ? Infinity : 3000"
|
|
||||||
@sl-after-hide="alerts.removeAlert(alert.id)"
|
|
||||||
>{{ alert.message }}</sl-alert
|
|
||||||
>
|
|
||||||
<RouterView />
|
<RouterView />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAuthTokenStore } from '@/store/auth'
|
import { useAuthTokenStore } from '@/store/auth'
|
||||||
import { useAlertsStore } from '@/store/useAlertsStore'
|
import ShowAlerts from '@/components/common/ShowAlerts.vue'
|
||||||
import { RouterView } from 'vue-router'
|
import { RouterView } from 'vue-router'
|
||||||
|
|
||||||
const alerts = useAlertsStore()
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -208,7 +208,6 @@ const props = defineProps<Props>()
|
|||||||
|
|
||||||
const shouldPaginate = toRef(() => props.paginate ?? true)
|
const shouldPaginate = toRef(() => props.paginate ?? true)
|
||||||
const auditFilter = toRef(() => props.auditFilter)
|
const auditFilter = toRef(() => props.auditFilter)
|
||||||
console.log(auditFilter.value)
|
|
||||||
const auditList = ref<AuditListResult>([])
|
const auditList = ref<AuditListResult>([])
|
||||||
const auditEntries = computed(() => auditList.value?.results)
|
const auditEntries = computed(() => auditList.value?.results)
|
||||||
const totalEntries = computed(() => auditList.value?.total)
|
const totalEntries = computed(() => auditList.value?.total)
|
||||||
|
|||||||
@ -80,10 +80,7 @@ const name = ref('')
|
|||||||
const description = ref('')
|
const description = ref('')
|
||||||
const sourcePrefix = ref('')
|
const sourcePrefix = ref('')
|
||||||
const policies = ref(['0.0.0.0/0', '::/0'])
|
const policies = ref(['0.0.0.0/0', '::/0'])
|
||||||
// This key is only here during testing.
|
const publicKey = ref('')
|
||||||
const publicKey = ref(
|
|
||||||
'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC737Yj7mbuBLDNbAuNGqhFF4Cvzd/ROq/QeQX0QIcPyZOoUtpXc7R/JIrdL6DXkPYXpN/IrUFoSeJQjV9Le+ewVxYELUPVhF0/nQhpBNE1Rjx2PRtJlfmywG5VRStgPQ+DSTDtgm4L0wPpnJiH3udkq/JFMHEYrVAF40QqNmR7AqYo1ZfEFk8YcQGb/S29JxWigq0qoJyufFENmSGNmabjqPAWJEf/oshMPaxwlDfTdmjeUWkPtsm10gi98XCwtnVCAVYZdVKeLSNpQCKUYVYWlycpahNczaITY9lehcMtux79uXTk2d4difra1Q4guw8oorUp1eRn/Al0BPeRb7x9WdgRs8wVY1kPD2796CTAQMkeBrOzGxwzwWhTf1XOuHG/wB5O2QSbcC6aMW9KAFmcCF+AOMb8Mv2Y5D7l/gbp938qTyZJ8ivP1/fy/88CWr+mrv5yP4HOZmNCyC9nMlAvrS/Kkg0tFU+NHFkDsmWpT3oar+VvGzkImEF6ip6Mzk8= testkey',
|
|
||||||
)
|
|
||||||
|
|
||||||
const nameField = ref<HTMLSlInputElement>()
|
const nameField = ref<HTMLSlInputElement>()
|
||||||
const sourceField = ref<HTMLSlInputElement>()
|
const sourceField = ref<HTMLSlInputElement>()
|
||||||
@ -169,15 +166,27 @@ function validatePublicKey() {
|
|||||||
setFieldValidation(publicKeyField, '')
|
setFieldValidation(publicKeyField, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resetValidation() {
|
||||||
|
setFieldValidation(nameField, '')
|
||||||
|
setFieldValidation(sourceField, '')
|
||||||
|
setFieldValidation(publicKeyField, '')
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.errors,
|
() => props.errors,
|
||||||
(errors) => {
|
(errors) => {
|
||||||
|
resetValidation()
|
||||||
const nameErrors = errors.filter((e) => e.loc.includes('name'))
|
const nameErrors = errors.filter((e) => e.loc.includes('name'))
|
||||||
|
const sourceErrors = errors.filter((e) => e.loc.includes('source'))
|
||||||
|
const publicKeyError = errors.filter((e) => e.loc.includes('public_key'))
|
||||||
if (nameErrors.length > 0) {
|
if (nameErrors.length > 0) {
|
||||||
console.log(nameErrors)
|
|
||||||
setFieldValidation(nameField, nameErrors[0].msg)
|
setFieldValidation(nameField, nameErrors[0].msg)
|
||||||
} else {
|
}
|
||||||
setFieldValidation(nameField, '')
|
if (sourceErrors.length > 0) {
|
||||||
|
setFieldValidation(sourceField, sourceErrors[0].msg)
|
||||||
|
}
|
||||||
|
if (publicKeyError.length > 0) {
|
||||||
|
setFieldValidation(publicKeyField, publicKeyErrors[0].msg)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<sl-alert
|
||||||
|
:variant="alert.type"
|
||||||
|
closable
|
||||||
|
:duration="['warning', 'error', 'danger'].includes(alert.type) ? Infinity : 3000"
|
||||||
|
ref="alertElement"
|
||||||
|
@sl-after-hide="alerts.removeAlert(alert.id)"
|
||||||
|
>
|
||||||
|
<sl-icon slot="icon" :name="alert.icon"></sl-icon>
|
||||||
|
<strong class="alert-title">{{ alert.title }}</strong
|
||||||
|
><br />
|
||||||
|
{{ alert.message }}
|
||||||
|
</sl-alert>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { useAlertsStore, Alert } from '@/store/useAlertsStore'
|
||||||
|
|
||||||
|
const alerts = useAlertsStore()
|
||||||
|
|
||||||
|
const props = defineProps<{ alert: Alert }>()
|
||||||
|
|
||||||
|
const alertElement = ref<HTMLSlAlertElement>()
|
||||||
|
|
||||||
|
function showToast() {
|
||||||
|
alertElement.value.toast()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(showToast)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.alert-title::first-letter {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<template v-for="alert in alerts.alerts" :key="alert.id">
|
||||||
|
<AlertToast :alert="alert" />
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||||
|
import AlertToast from '@/components/common/AlertToast.vue'
|
||||||
|
|
||||||
|
const alerts = useAlertsStore()
|
||||||
|
</script>
|
||||||
@ -16,9 +16,12 @@
|
|||||||
<sl-button variant="default" outline @click="emit('cancel')"> Cancel</sl-button>
|
<sl-button variant="default" outline @click="emit('cancel')"> Cancel</sl-button>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, toRef } from 'vue'
|
||||||
import { SshecretAdmin } from '@/client'
|
import { SshecretAdmin } from '@/client'
|
||||||
import type { ClientSecretGroup } from '@/client'
|
import type { ClientSecretGroup } from '@/client'
|
||||||
import { ref, onMounted, toRef } from 'vue'
|
|
||||||
|
import { assertSdkResponseOk } from '@/api/assertSdkResponseOk'
|
||||||
|
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||||
|
|
||||||
const props = defineProps<{ self: string }>()
|
const props = defineProps<{ self: string }>()
|
||||||
const groups = ref<ClientSecretGroup[]>([])
|
const groups = ref<ClientSecretGroup[]>([])
|
||||||
@ -33,8 +36,11 @@ async function getGroups() {
|
|||||||
const response = await SshecretAdmin.getSecretGroupsApiV1SecretsGroupsGet({
|
const response = await SshecretAdmin.getSecretGroupsApiV1SecretsGroupsGet({
|
||||||
query: { flat: true },
|
query: { flat: true },
|
||||||
})
|
})
|
||||||
if (response.data) {
|
try {
|
||||||
groups.value = response.data.groups
|
const responseData = assertSdkResponseOk(response)
|
||||||
|
groups.value = responseData.groups
|
||||||
|
} catch (err) {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Could not fetch groups from the backend')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<template v-if="groups">
|
||||||
|
<sl-select
|
||||||
|
placeholder="Target parent"
|
||||||
|
hoist
|
||||||
|
:value="selectedPath"
|
||||||
|
@sl-change="selectedPath = $event.target.value"
|
||||||
|
>
|
||||||
|
<sl-option v-for="group in groups" :key="group.path" :value="group.path">{{
|
||||||
|
group.path
|
||||||
|
}}</sl-option>
|
||||||
|
</sl-select>
|
||||||
|
</template>
|
||||||
|
<sl-button variant="success" outline @click="selectPath" class="mr-2"> Move</sl-button>
|
||||||
|
<sl-button variant="default" outline @click="emit('cancel')"> Cancel</sl-button>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { SshecretAdmin } from '@/client'
|
||||||
|
import type { ClientSecretGroup } from '@/client'
|
||||||
|
import { ref, onMounted, toRef } from 'vue'
|
||||||
|
import { assertSdkResponseOk } from '@/api/assertSdkResponseOk'
|
||||||
|
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
existingPath?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
const groups = ref<ClientSecretGroup[]>([])
|
||||||
|
|
||||||
|
const emit = defineEmits<{ (e: 'selected', data: string): void; (e: 'cancel'): void }>()
|
||||||
|
|
||||||
|
const alerts = useAlertsStore()
|
||||||
|
|
||||||
|
const selectedPath = ref('')
|
||||||
|
|
||||||
|
async function getGroups() {
|
||||||
|
const response = await SshecretAdmin.getSecretGroupsApiV1SecretsGroupsGet({
|
||||||
|
query: { flat: true },
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
const responseData = assertSdkResponseOk(response)
|
||||||
|
if (props.existingPath) {
|
||||||
|
groups.value = responseData.groups.filter((entry) => entry.path !== props.existingPath)
|
||||||
|
} else {
|
||||||
|
groups.value = responseData.groups
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Could not fetch groups from the backend')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPath() {
|
||||||
|
emit('selected', selectedPath.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(getGroups)
|
||||||
|
</script>
|
||||||
@ -100,12 +100,25 @@
|
|||||||
>
|
>
|
||||||
{{ secret.group.path }}
|
{{ secret.group.path }}
|
||||||
<div class="mt-2 float-right">
|
<div class="mt-2 float-right">
|
||||||
<sl-button size="medium" variant="default" outline>
|
<sl-button size="medium" variant="default" outline @click="showMove = true">
|
||||||
<sl-icon slot="prefix" name="box-arrow-in-right"></sl-icon>
|
<sl-icon slot="prefix" name="box-arrow-in-right"></sl-icon>
|
||||||
Move
|
Move
|
||||||
</sl-button>
|
</sl-button>
|
||||||
</div>
|
</div>
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
|
<dd
|
||||||
|
class="mt-1 text-sm/6 text-gray-700 sm:col-span-2 sm:mt-0 dark:text-gray-300"
|
||||||
|
v-else
|
||||||
|
>
|
||||||
|
Not in any group
|
||||||
|
<div class="mt-2 float-right">
|
||||||
|
<sl-button size="medium" variant="success" outline @click="showMove = true">
|
||||||
|
<sl-icon slot="prefix" name="folder-plus"></sl-icon>
|
||||||
|
Add to group
|
||||||
|
</sl-button>
|
||||||
|
</div>
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
@ -179,6 +192,13 @@
|
|||||||
<sl-button variant="danger" @click="deleteSecret">Delete</sl-button>
|
<sl-button variant="danger" @click="deleteSecret">Delete</sl-button>
|
||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
<Dialog label="Move secret to group" :open="showMove" @hide="showMove = false">
|
||||||
|
<MoveSecretGroup
|
||||||
|
:existingPath="existingGroupPath"
|
||||||
|
@selected="moveGroup"
|
||||||
|
@cancel="showMove = false"
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -188,6 +208,7 @@ import AuditTable from '@/components/audit/AuditTable.vue'
|
|||||||
|
|
||||||
import AddSecretToClients from '@/components/secrets/AddSecretToClients.vue'
|
import AddSecretToClients from '@/components/secrets/AddSecretToClients.vue'
|
||||||
import Dialog from '@/components/common/Dialog.vue'
|
import Dialog from '@/components/common/Dialog.vue'
|
||||||
|
import MoveSecretGroup from '@/components/secrets/MoveSecretGroup.vue'
|
||||||
|
|
||||||
const props = defineProps<{ secret: SecretView }>()
|
const props = defineProps<{ secret: SecretView }>()
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@ -195,17 +216,15 @@ const emit = defineEmits<{
|
|||||||
(e: 'delete'): void
|
(e: 'delete'): void
|
||||||
(e: 'addClient', data: string): void
|
(e: 'addClient', data: string): void
|
||||||
(e: 'removeClient', data: string): void
|
(e: 'removeClient', data: string): void
|
||||||
|
(e: 'moveGroup', data: string): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const secret = ref<Secret>(props.secret)
|
const secret = ref<Secret>(props.secret)
|
||||||
|
|
||||||
const clients = computed(() => props.secret?.clients ?? [])
|
const clients = computed(() => props.secret?.clients ?? [])
|
||||||
|
|
||||||
const secretValue = ref<string | null>(secret.value?.secret)
|
const secretValue = ref<string | null>(secret.value?.secret)
|
||||||
|
|
||||||
const addDialog = ref<boolean>(false)
|
const addDialog = ref<boolean>(false)
|
||||||
|
|
||||||
const showConfirm = ref<boolean>(false)
|
const showConfirm = ref<boolean>(false)
|
||||||
|
const showMove = ref<boolean>(false)
|
||||||
|
|
||||||
const secretChanged = computed(() => {
|
const secretChanged = computed(() => {
|
||||||
if (!secretValue.value) {
|
if (!secretValue.value) {
|
||||||
@ -226,6 +245,13 @@ function handleHide(event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveGroup(path: string) {
|
||||||
|
emit('moveGroup', path)
|
||||||
|
showMove.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingGroupPath = computed(() => secret.value.group?.path)
|
||||||
|
|
||||||
function updateSecret() {
|
function updateSecret() {
|
||||||
emit('update', secretValue.value)
|
emit('update', secretValue.value)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,17 @@ import { defineStore } from 'pinia'
|
|||||||
interface Alert {
|
interface Alert {
|
||||||
id: number
|
id: number
|
||||||
message: string
|
message: string
|
||||||
type: 'info' | 'success' | 'warning' | 'error'
|
title?: string
|
||||||
|
type: 'info' | 'success' | 'warning' | 'error' | 'danger'
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconMap = {
|
||||||
|
'info': 'info-circle',
|
||||||
|
'success': 'check2-circle',
|
||||||
|
'warning': 'exclamation-triangle',
|
||||||
|
'error': 'exclamation-octagon',
|
||||||
|
'danger': 'exclamation-octagon',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAlertsStore = defineStore('alerts', {
|
export const useAlertsStore = defineStore('alerts', {
|
||||||
@ -12,11 +22,24 @@ export const useAlertsStore = defineStore('alerts', {
|
|||||||
alerts: [] as Alert[],
|
alerts: [] as Alert[],
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
showAlert(message: string, type: Alert['type'] = 'info') {
|
showAlert(message: string, type: Alert['type'] = 'info', title?: string) {
|
||||||
|
if (type === 'error') {
|
||||||
|
type = 'danger'
|
||||||
|
}
|
||||||
|
if (!title) {
|
||||||
|
if (type === 'danger') {
|
||||||
|
title = 'Error'
|
||||||
|
} else {
|
||||||
|
title = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const icon = iconMap[type]
|
||||||
this.alerts.push({
|
this.alerts.push({
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
message,
|
message,
|
||||||
|
title,
|
||||||
type,
|
type,
|
||||||
|
icon,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
removeAlert(id: number) {
|
removeAlert(id: number) {
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
@delete="deleteSecret"
|
@delete="deleteSecret"
|
||||||
@addClient="addSecretToClient"
|
@addClient="addSecretToClient"
|
||||||
@removeClient="removeClientSecret"
|
@removeClient="removeClientSecret"
|
||||||
|
@moveGroup="moveGroup"
|
||||||
v-if="secret"
|
v-if="secret"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -17,16 +18,20 @@ import { ref, watch, onMounted } from 'vue'
|
|||||||
import SecretDetail from '@/components/secrets/SecretDetail.vue'
|
import SecretDetail from '@/components/secrets/SecretDetail.vue'
|
||||||
import SecretSkeleton from '@/components/secrets/SecretSkeleton.vue'
|
import SecretSkeleton from '@/components/secrets/SecretSkeleton.vue'
|
||||||
import NotFound from '@/components/common/NotFound.vue'
|
import NotFound from '@/components/common/NotFound.vue'
|
||||||
|
import { assertSdkResponseOk } from '@/api/assertSdkResponseOk'
|
||||||
import { ApiError, NotFoundError, ValidationError } from '@/api/errors'
|
import { ApiError, NotFoundError, ValidationError } from '@/api/errors'
|
||||||
import { useTreeState } from '@/store/useTreeState'
|
import { useTreeState } from '@/store/useTreeState'
|
||||||
import { useAlertsStore } from '@/store/useAlertsStore'
|
import { useAlertsStore } from '@/store/useAlertsStore'
|
||||||
|
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
import type { SecretView } from '@/client/types.gen.ts'
|
import type { SecretView } from '@/client/types.gen.ts'
|
||||||
import { SshecretAdmin } from '@/client'
|
import { SshecretAdmin } from '@/client'
|
||||||
|
|
||||||
const alerts = useAlertsStore()
|
const alerts = useAlertsStore()
|
||||||
const props = defineProps<{ id: string | null; parentId: string | null }>()
|
const props = defineProps<{ id: string | null; parentId: string | null }>()
|
||||||
const secret = ref<SecretView>()
|
const secret = ref<SecretView>()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const treeState = useTreeState()
|
const treeState = useTreeState()
|
||||||
|
|
||||||
@ -68,38 +73,75 @@ async function updateSecretValue(value: string) {
|
|||||||
async function deleteSecret(clients: string[]) {
|
async function deleteSecret(clients: string[]) {
|
||||||
// Delete the whole secret
|
// Delete the whole secret
|
||||||
if (props.id) {
|
if (props.id) {
|
||||||
await SshecretAdmin.deleteSecretApiV1SecretsNameDelete({ path: { name: props.id } })
|
const response = await SshecretAdmin.deleteSecretApiV1SecretsNameDelete({
|
||||||
for (const clientId in clients) {
|
path: { name: props.id },
|
||||||
await treeState.refreshClient(clientId)
|
})
|
||||||
|
try {
|
||||||
|
assertSdkResponseOk(response)
|
||||||
|
for (const clientId in clients) {
|
||||||
|
await treeState.refreshClient(clientId)
|
||||||
|
}
|
||||||
|
await treeState.getSecretGroups()
|
||||||
|
treeState.bumpGroupRevision()
|
||||||
|
router.go(-1)
|
||||||
|
} catch (err) {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Error deleting secret')
|
||||||
}
|
}
|
||||||
await treeState.getSecretGroups()
|
|
||||||
treeState.bumpGroupRevision()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addSecretToClient(clientId: string) {
|
async function addSecretToClient(clientId: string) {
|
||||||
if (props.id) {
|
if (props.id) {
|
||||||
await SshecretAdmin.addSecretToClientApiV1ClientsIdSecretsSecretNamePut({
|
const response = await SshecretAdmin.addSecretToClientApiV1ClientsIdSecretsSecretNamePut({
|
||||||
path: {
|
path: {
|
||||||
id: clientId,
|
id: clientId,
|
||||||
secret_name: props.id,
|
secret_name: props.id,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
await treeState.refreshClient(clientId)
|
try {
|
||||||
await loadSecret()
|
assertSdkResponseOk(response)
|
||||||
|
await treeState.refreshClient(clientId)
|
||||||
|
await loadSecret()
|
||||||
|
} catch (err) {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Failed to add secret to client')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeClientSecret(clientId: string) {
|
async function removeClientSecret(clientId: string) {
|
||||||
if (props.id) {
|
if (props.id) {
|
||||||
await SshecretAdmin.deleteSecretFromClientApiV1ClientsIdSecretsSecretNameDelete({
|
const response =
|
||||||
path: {
|
await SshecretAdmin.deleteSecretFromClientApiV1ClientsIdSecretsSecretNameDelete({
|
||||||
id: clientId,
|
path: {
|
||||||
secret_name: props.id,
|
id: clientId,
|
||||||
},
|
secret_name: props.id,
|
||||||
})
|
},
|
||||||
await treeState.refreshClient(clientId)
|
})
|
||||||
|
try {
|
||||||
|
assertSdkResponseOk(response)
|
||||||
|
await treeState.refreshClient(clientId)
|
||||||
|
await loadSecret()
|
||||||
|
} catch (err) {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Failed to remove secret from client')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function moveGroup(path) {
|
||||||
|
// Move secret to a group.
|
||||||
|
const data = {
|
||||||
|
secret_name: secret.value.name,
|
||||||
|
group_path: path,
|
||||||
|
}
|
||||||
|
const response = await SshecretAdmin.assignSecretGroupApiV1SecretsSetGroupPost({ body: data })
|
||||||
|
try {
|
||||||
|
assertSdkResponseOk(response)
|
||||||
await loadSecret()
|
await loadSecret()
|
||||||
|
await treeState.getSecretGroups()
|
||||||
|
treeState.bumpGroupRevision()
|
||||||
|
alerts.showAlert('Secret moved', 'success')
|
||||||
|
} catch (err) {
|
||||||
|
alerts.showAlert(err.message, 'error', 'Failed to move secret to group')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(loadSecret)
|
onMounted(loadSecret)
|
||||||
|
|||||||
Reference in New Issue
Block a user