[go: nahoru, domu]

Skip to content

Commit

Permalink
feat(ui): added a role selection in api keys feature
Browse files Browse the repository at this point in the history
This commit adds the role attribute on the Api Keys feature and
created a new store to encapsulate all api keys methods.
  • Loading branch information
luannmoreira authored and gustavosbarreto committed Jun 10, 2024
1 parent 61b708b commit 440c16d
Show file tree
Hide file tree
Showing 20 changed files with 1,002 additions and 511 deletions.
684 changes: 518 additions & 166 deletions ui/src/api/client/api.ts

Large diffs are not rendered by default.

33 changes: 19 additions & 14 deletions ui/src/components/Namespace/NamespaceApiKeyList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
<template v-slot:rows>
<tr v-for="(item, i) in keyList" :key="i">
<td :class="formatKey(item.expires_in) ? 'text-warning' : ''">
<v-icon class="mr-1" :icon="formatKey(item.expires_in) ? 'mdi-clock-alert-outline' : 'mdi-key-outline'" data-test="key-icon" />
<v-icon class="mr-1" :icon="formatKey(item.expires_in) ? 'mdi-clock-alert-outline' : 'mdi-key-outline'" />
{{ item.name }}
</td>
<td :class="formatKey(item.expires_in) ? 'text-warning text-center' : 'text-center'" data-test="key-name">
{{ item.role }}
</td>
<td :class="formatKey(item.expires_in) ? 'text-warning text-center' : 'text-center'" data-test="key-name">
{{ formatDate(item.expires_in) }}
</td>
Expand All @@ -43,6 +46,7 @@
<NamespaceEditApiKey
:key-name="item.name"
:key-id="item.id"
:key-role="item.role"
:has-authorization="hasAuthorizationRemoveKey()"
:disabled="formatKey(item.expires_in)"
@update="refresh()"
Expand All @@ -60,7 +64,7 @@
<template v-slot:activator="{ props }">
<div v-bind="props">
<NamespaceDeleteApiKey
:keyId="item.id"
:keyId="item.name"
:has-authorization="hasAuthorizationRemoveKey()"
@update="refresh()"
/>
Expand Down Expand Up @@ -96,6 +100,10 @@ const headers = [
value: "name",
sortable: true,
},
{
text: "Role",
value: "role",
},
{
text: "Expiration Date",
value: "expires_in",
Expand All @@ -111,9 +119,9 @@ const itemsPerPage = ref(10);
const page = ref(1);
const store = useStore();
const numberKeys = computed<number>(
() => store.getters["auth/getNumberApiKeys"],
() => store.getters["apiKeys/getNumberApiKeys"],
);
const keyList = computed(() => store.getters["auth/apiKeyList"]);
const keyList = computed(() => store.getters["apiKeys/apiKeyList"]);
const hasAuthorizationRemoveKey = () => {
const role = store.getters["auth/role"];
if (role !== "") {
Expand Down Expand Up @@ -150,17 +158,14 @@ const formatDate = (unixTime: number): string => {
: `Expires on ${expiryDate.format(format)}.`;
};
const tenant = computed(() => localStorage.getItem("tenant"));
const getKey = async (perPagaeValue: number, pageValue: number) => {
try {
loading.value = true;
await store.dispatch("auth/getApiKey", {
tenant: tenant.value,
perPage: perPagaeValue,
await store.dispatch("apiKeys/getApiKey", {
page: pageValue,
sortStatusField: store.getters["auth/getSortStatusField"],
sortStatusString: store.getters["auth/getSortStatusString"],
perPage: perPagaeValue,
sortStatusField: store.getters["apiKeys/getSortStatusField"],
sortStatusString: store.getters["apiKeys/getSortStatusString"],
});
} catch (error: unknown) {
if (axios.isAxiosError(error)) {
Expand Down Expand Up @@ -210,8 +215,8 @@ watch(itemsPerPage, async (newItemsPerPage) => {
});
const sortByItem = async (field: string) => {
let sortStatusString = store.getters["auth/getSortStatusString"];
const sortStatusField = store.getters["auth/getSortStatusField"];
let sortStatusString = store.getters["apiKeys/getSortStatusString"];
const sortStatusField = store.getters["apiKeys/getSortStatusField"];
if (field !== sortStatusField && sortStatusField) {
if (sortStatusString === "asc") {
Expand All @@ -228,7 +233,7 @@ const sortByItem = async (field: string) => {
} else {
sortStatusString = "asc";
}
await store.dispatch("auth/setSortStatus", {
await store.dispatch("apiKeys/setSortStatus", {
sortStatusField: field,
sortStatusString,
});
Expand Down
8 changes: 3 additions & 5 deletions ui/src/components/Namespace/NamespaceDeleteApiKey.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
</template>

<script setup lang="ts">
import { ref, computed } from "vue";
import { ref } from "vue";
import {
INotificationsError,
INotificationsSuccess,
Expand All @@ -64,7 +64,6 @@ const props = defineProps({
const emit = defineEmits(["update"]);
const showDialog = ref(false);
const store = useStore();
const tenant = computed(() => localStorage.getItem("tenant"));
const update = () => {
emit("update");
Expand All @@ -73,9 +72,8 @@ const update = () => {
const remove = async () => {
try {
await store.dispatch("auth/removeApiKey", {
tenant: tenant.value,
id: props.keyId,
await store.dispatch("apiKeys/removeApiKey", {
key: props.keyId,
});
update();
store.dispatch(
Expand Down
95 changes: 74 additions & 21 deletions ui/src/components/Namespace/NamespaceEditApiKey.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,37 @@
<v-divider />

<v-card-text class="mt-3">
<v-text-field
v-model="keyInput"
label="key name"
prepend-icon="mdi-key-outline"
:error-messages="keyInputError"
required
variant="underlined"
data-test="key-name-text"
messages="Please note that the new name must be unique

<v-row>
<v-col>
<v-text-field
v-model="keyInput"
label="key name"
prepend-icon="mdi-key-outline"
:error-messages="keyInputError"
required
variant="underlined"
data-test="key-name-text"
messages="Please note that the new name must be unique
and not already in use by another key."
/>
/>

</v-col>
</v-row>
<v-row>
<v-col>
<v-select
v-if="hasAuthorization"
v-model="selectedRole"
label="Key Role"
:items="itemsRoles"
:item-props="true"
variant="outlined"
return-object
data-test="namespace-generate-role"
/>
</v-col>
</v-row>
</v-card-text>

<v-card-actions>
Expand Down Expand Up @@ -61,7 +81,7 @@ const props = defineProps({
type: String,
required: true,
},
keyId: {
keyRole: {
type: String,
required: true,
},
Expand All @@ -78,15 +98,23 @@ const emit = defineEmits(["update"]);
const showDialog = ref(false);
const store = useStore();
const keyGetter = computed(() => props.keyName);
const tenant = computed(() => localStorage.getItem("tenant"));
const isOwner = computed(() => store.getters["auth/role"] === "owner");
const {
value: keyInput,
errorMessage: keyInputError,
setErrors: setKeyInputError,
} = useField<string | undefined>("name", yup.string().required(), {
initialValue: keyGetter.value,
});
} = useField<string | undefined>(
"name",
yup
.string()
.required()
.min(3)
.max(20)
.matches(/^(?!.*\s).*$/, "This field cannot contain any blankspaces"),
{
initialValue: keyGetter.value,
},
);
const open = () => {
showDialog.value = true;
Expand All @@ -98,13 +126,38 @@ const update = () => {
showDialog.value = false;
};
const itemsRoles = [
{
title: "observer",
value: "observer",
},
{
title: "operator",
value: "operator",
},
{
title: "administrator",
value: "administrator",
disabled: !props.hasAuthorization || !isOwner.value,
},
];
const selectedRole = ref(itemsRoles.find((role) => role.value === props.keyRole) || itemsRoles[0]);
const edit = async () => {
const equalName = props.keyName === keyInput.value;
const equalRole = props.keyRole === selectedRole.value.value;
const payload: { key: string; name?: string; role?: string } = { key: props.keyName };
if (!equalName) {
payload.name = keyInput.value;
}
if (!equalRole) {
payload.role = selectedRole.value.value;
}
try {
await store.dispatch("auth/editApiKey", {
tenant: tenant.value,
name: keyInput.value,
id: props.keyId,
});
await store.dispatch("apiKeys/editApiKey", payload);
update();
store.dispatch(
"snackbar/showSnackbarSuccessAction",
Expand Down
Loading

0 comments on commit 440c16d

Please sign in to comment.