Skip to content

Commit a3762be

Browse files
committed
refactor(ui): new settings interface
- New appearance for the Settings inputs. - New Unitary Tests to insure the correct behavior on the refactored components
1 parent c05f40f commit a3762be

31 files changed

+1173
-1305
lines changed

ui/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"@fortawesome/free-brands-svg-icons": "^6.4.0",
2222
"@fortawesome/free-regular-svg-icons": "^6.4.0",
2323
"@fortawesome/free-solid-svg-icons": "^6.4.0",
24-
"@mdi/font": "7.2.96",
24+
"@mdi/font": "^7.4.47",
2525
"@productdevbook/chatwoot": "github:shellhub-io/chatwoot#build",
2626
"@rollup/plugin-inject": "^5.0.3",
2727
"@rushstack/eslint-patch": "^1.2.0",

ui/src/authorizer.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const {
5050
publicKeyRemove,
5151
// Namespace
5252
namespaceCreate,
53-
NamespaceEdit,
53+
namespaceEdit,
5454
namespaceAddMember,
5555
namespaceEditMember,
5656
namespaceRemoveMember,
@@ -106,7 +106,7 @@ export const actions: { [key: string]: any } = {
106106
},
107107
namespace: {
108108
create: namespaceCreate,
109-
rename: NamespaceEdit,
109+
rename: namespaceEdit,
110110
addMember: namespaceAddMember,
111111
editMember: namespaceEditMember,
112112
removeMember: namespaceRemoveMember,

ui/src/components/Namespace/NamespaceDelete.vue

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,8 @@
11
<template>
2-
<v-tooltip location="bottom" class="text-center" :disabled="hasAuthorization">
3-
<template v-slot:activator="{ props }">
4-
<div v-bind="props">
5-
<v-btn
6-
:disabled="!hasAuthorization"
7-
color="red darken-1"
8-
variant="outlined"
9-
data-test="delete-btn"
10-
@click="dialog = !dialog"
11-
>
12-
Delete namespace
13-
</v-btn>
14-
</div>
15-
</template>
16-
<span> You don't have this kind of authorization. </span>
17-
</v-tooltip>
18-
192
<v-dialog v-model="dialog" max-width="540">
203
<v-card data-test="namespaceDelete-dialog" class="bg-v-theme-surface">
214
<v-card-title class="text-h5 pa-4 bg-primary">
22-
Namespace Deletion Restriction
5+
Namespace Deletion
236
</v-card-title>
247

258
<v-card-text class="mt-4 mb-3 pb-1">
@@ -55,7 +38,7 @@
5538
variant="text"
5639
data-test="remove-btn"
5740
@click="remove()"
58-
:disabled="billingActive"
41+
:disabled="billingActive || hasAuthorization"
5942
>
6043
Remove
6144
</v-btn>
@@ -88,15 +71,15 @@ const props = defineProps({
8871
const emit = defineEmits(["billing-in-debt"]);
8972
const store = useStore();
9073
const router = useRouter();
91-
const dialog = ref(false);
74+
const dialog = defineModel({ default: false });
9275
const name = ref("");
9376
const tenant = computed(() => props.tenant);
9477
const billingActive = computed(() => store.getters["billing/active"]);
9578
9679
const hasAuthorization = computed(() => {
9780
const role = store.getters["auth/role"];
9881
if (role !== "") {
99-
return hasPermission(
82+
return !hasPermission(
10083
authorizer.role[role],
10184
actions.namespace.remove,
10285
);
Lines changed: 91 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,56 @@
11
<template>
2-
<v-row v-bind="$attrs">
3-
<v-col data-test="namespace-title">
4-
<h3>Namespace</h3>
5-
</v-col>
6-
7-
<v-spacer />
8-
9-
<v-col md="auto" class="ml-auto">
10-
<v-tooltip
11-
location="bottom"
12-
class="text-center"
13-
:disabled="hasAuthorizationRenameNamespace()"
14-
>
15-
<template v-slot:activator="{ props }">
16-
<div v-bind="props">
17-
<v-btn
18-
v-if="editBtn"
19-
:disabled="!hasAuthorizationRenameNamespace() || (!!nameError || !!connectionAnnouncementError)"
20-
color="primary"
21-
@click="editBtn = false;"
22-
data-test="edit-btn"
23-
>
24-
Edit Namespace
25-
</v-btn>
26-
<v-btn
27-
v-else
28-
:disabled="!!nameError || !!connectionAnnouncementError"
29-
color="primary"
30-
@click="editNamespace"
31-
data-test="save-btn"
32-
>
33-
Save Namespace
34-
</v-btn>
35-
</div>
36-
</template>
37-
<span> You don't have this kind of authorization. </span>
38-
</v-tooltip>
39-
</v-col>
40-
</v-row>
41-
42-
<div class="mt-4 mb-2">
43-
<v-text-field
44-
:disabled="validateInput"
45-
v-model="name"
46-
class="ml-3"
47-
label="Name"
48-
:error-messages="nameError"
49-
variant="underlined"
50-
required
51-
data-test="name-text"
52-
/>
53-
</div>
54-
55-
<div class="mb-2">
56-
<v-textarea
57-
:disabled="validateInput"
58-
v-model="connectionAnnouncement"
59-
label="Connection Announcement"
60-
:error-messages="connectionAnnouncementError"
61-
data-test="connectionAnnouncement-text"
62-
variant="underlined"
63-
hint="A connection announcement is a custom message written
2+
<v-dialog v-model="show" max-width="700" @click:outside="close">
3+
<v-card data-test="password-change-card" class="bg-v-theme-surface">
4+
<v-card-title class="text-h5 pa-4 bg-primary" data-test="title">
5+
Change Connection Announcement
6+
</v-card-title>
7+
8+
<v-card-text class="mt-4 mb-3 pb-1">
9+
<div class="mt-4 pl-4 pr-4">
10+
<v-textarea
11+
v-model="connectionAnnouncement"
12+
label="Connection Announcement"
13+
:error-messages="connectionAnnouncementError"
14+
data-test="connectionAnnouncement-text"
15+
variant="underlined"
16+
hint="A connection announcement is a custom message written
6417
during a session when a connection is established on a device
6518
within the namespace."
66-
persistent-hint
67-
required
68-
/>
69-
</div>
19+
persistent-hint
20+
required
21+
auto-grow
22+
max-rows="25"
23+
/>
24+
</div>
25+
</v-card-text>
26+
27+
<v-card-actions>
28+
<v-spacer />
29+
30+
<v-btn variant="text" data-test="close-btn" @click="close">
31+
Cancel
32+
</v-btn>
7033

34+
<v-btn
35+
color="primary"
36+
variant="text"
37+
data-test="change-connection-btn"
38+
:disabled="connectionAnnouncementError"
39+
@click="updateAnnouncement()"
40+
>
41+
Save Announcement
42+
</v-btn>
43+
</v-card-actions>
44+
</v-card>
45+
</v-dialog>
7146
</template>
7247

7348
<script setup lang="ts">
74-
import { computed, onMounted, ref, watch } from "vue";
49+
import { computed, onMounted, watch } from "vue";
7550
import { useField } from "vee-validate";
76-
import axios, { AxiosError } from "axios";
51+
import axios from "axios";
7752
import * as yup from "yup";
7853
import { useStore } from "../../store";
79-
import hasPermission from "../../utils/permission";
80-
import { actions, authorizer } from "../../authorizer";
8154
import {
8255
INotificationsError,
8356
INotificationsSuccess,
@@ -87,24 +60,8 @@ import handleError from "@/utils/handleError";
8760
const store = useStore();
8861
const namespace = computed(() => store.getters["namespaces/get"]);
8962
const tenant = computed(() => store.getters["auth/tenant"]);
90-
const editBtn = ref(true);
91-
const validateInput = computed(() => editBtn.value === true);
92-
const {
93-
value: name,
94-
errorMessage: nameError,
95-
setErrors: setNameError,
96-
} = useField<string>(
97-
"name",
98-
yup
99-
.string()
100-
.min(3, "Your namespace should be 3-30 characters long")
101-
.max(30, "Your namespace should be 3-30 characters long")
102-
.required()
103-
.matches(/^[^.]*$/, "The name must not contain dots"),
104-
{
105-
initialValue: "",
106-
},
107-
);
63+
const show = defineModel({ default: false });
64+
const emit = defineEmits(["update"]);
10865
10966
const {
11067
value: connectionAnnouncement,
@@ -120,8 +77,12 @@ const {
12077
},
12178
);
12279
80+
const close = () => {
81+
connectionAnnouncement.value = namespace.value.settings.connection_announcement;
82+
show.value = false;
83+
};
84+
12385
watch(namespace, (ns) => {
124-
name.value = ns.name;
12586
connectionAnnouncement.value = ns.settings.connection_announcement;
12687
});
12788
@@ -130,59 +91,53 @@ onMounted(() => {
13091
store.dispatch("namespaces/get", tenant.value);
13192
});
13293
133-
const hasAuthorizationRenameNamespace = () => {
134-
const role = store.getters["auth/role"];
135-
if (role !== "") {
136-
return hasPermission(authorizer.role[role], actions.namespace.rename);
137-
}
138-
139-
return false;
140-
};
141-
142-
const editNamespace = async () => {
143-
if (!nameError.value) {
144-
try {
145-
await store.dispatch("namespaces/put", {
146-
id: tenant.value,
147-
name: name.value,
148-
settings: {
149-
connection_announcement: connectionAnnouncement.value,
150-
},
151-
});
152-
await store.dispatch("namespaces/fetch", {
153-
page: 1,
154-
perPage: 10,
155-
filter: "",
156-
});
157-
await store.dispatch("namespaces/get", tenant.value);
158-
store.dispatch(
159-
"snackbar/showSnackbarSuccessAction",
160-
INotificationsSuccess.namespaceEdit,
161-
);
162-
editBtn.value = true;
163-
} catch (error: unknown) {
164-
if (axios.isAxiosError(error)) {
165-
const axiosError = error as AxiosError;
166-
if (axiosError.response?.status === 400) {
167-
setNameError("This name is not valid");
168-
setConnectionAnnouncementError("This message is not valid");
169-
} else if (axiosError.response?.status === 409) {
170-
setNameError("name used already");
171-
} else {
172-
store.dispatch(
173-
"snackbar/showSnackbarErrorAction",
174-
INotificationsError.namespaceEdit,
175-
);
176-
handleError(error);
177-
}
178-
} else {
94+
const handleUpdateNameError = (error: unknown): void => {
95+
if (axios.isAxiosError(error)) {
96+
switch (error.response?.status) {
97+
case 400:
98+
setConnectionAnnouncementError("This message is not valid");
99+
break;
100+
default:
179101
store.dispatch(
180102
"snackbar/showSnackbarErrorAction",
181103
INotificationsError.namespaceEdit,
182104
);
183105
handleError(error);
184-
}
185106
}
186107
}
108+
109+
store.dispatch(
110+
"snackbar/showSnackbarErrorAction",
111+
INotificationsError.namespaceEdit,
112+
);
113+
handleError(error);
114+
};
115+
116+
const updateAnnouncement = async () => {
117+
try {
118+
await store.dispatch("namespaces/put", {
119+
id: tenant.value,
120+
settings: {
121+
connection_announcement: connectionAnnouncement.value,
122+
},
123+
});
124+
125+
await store.dispatch("namespaces/fetch", {
126+
page: 1,
127+
perPage: 10,
128+
filter: "",
129+
});
130+
131+
emit("update");
132+
store.dispatch(
133+
"snackbar/showSnackbarSuccessAction",
134+
INotificationsSuccess.namespaceEdit,
135+
);
136+
show.value = false;
137+
} catch (error) {
138+
handleUpdateNameError(error);
139+
}
187140
};
141+
142+
defineExpose({ show });
188143
</script>

0 commit comments

Comments
 (0)