Skip to content

Commit 2b5ef20

Browse files
luannmoreiraotavio
authored andcommitted
refactor(ui): streamline dialog structure and inputs
Simplified markup by collapsing multiline tags and aligning props. Refactored table headers to use a loop with dynamic labels. Created a function to normalize the new Headers variable logic on tests. Improved device search behavior and keyboard shortcut handling. Fixed test selectors to match updated header labeling logic.
1 parent 3430789 commit 2b5ef20

File tree

3 files changed

+76
-89
lines changed

3 files changed

+76
-89
lines changed

ui/src/components/QuickConnection/QuickConnection.vue

+74-87
Original file line numberDiff line numberDiff line change
@@ -12,180 +12,167 @@
1212
>
1313
Quick Connect
1414
</v-btn>
15+
1516
<div>
16-
<p
17-
class="text-caption text-md font-weight-bold text-grey-darken-1 ma-1"
18-
data-test="quick-connect-instructions"
19-
>
17+
<p class="text-caption text-md font-weight-bold text-grey-darken-1 ma-1" data-test="quick-connect-instructions">
2018
Press <v-chip density="compact" size="small" label>Ctrl+K</v-chip> to Quick Connect!
2119
</p>
2220
</div>
23-
<v-dialog
24-
v-model="dialog"
25-
width="1000"
26-
transition="dialog-bottom-transition"
27-
>
21+
22+
<v-dialog v-model="dialog" width="1000" transition="dialog-bottom-transition">
2823
<v-card class="bg-v-theme-surface content" min-height="700" max-height="700">
2924
<div class="pa-5">
3025
<v-row>
3126
<v-col>
3227
<v-text-field
3328
label="Search your online devices!"
34-
variant="solo"
29+
variant="outlined"
30+
bg-color="bg-v-theme-surface"
3531
color="primary"
3632
single-line
3733
hide-details
3834
v-model.trim="filter"
39-
v-on:keyup="searchDevices"
35+
@keyup="searchDevices"
4036
prepend-inner-icon="mdi-magnify"
4137
density="comfortable"
4238
data-test="search-text"
4339
autofocus
44-
class="shrink mx-1"
40+
class="shrink mx-1 mt-2"
4541
/>
42+
4643
</v-col>
4744
</v-row>
4845
</div>
46+
4947
<v-card-text class="mt-4 mb-0 pb-1 flex">
5048
<v-row>
51-
<v-col>
52-
<p class="text-body-2 mb-2 font-weight-bold text-center" data-test="hostname-header">
53-
Hostname
54-
</p>
55-
</v-col>
56-
<v-col>
57-
<p class="text-body-2 mb-2 font-weight-bold text-center" data-test="os-header">
58-
Operating System
59-
</p>
60-
</v-col>
61-
<v-col>
62-
<p class="text-body-2 mb-2 font-weight-bold text-center" data-test="sshid-header">
63-
SSHID
64-
</p>
65-
</v-col>
66-
<v-col>
67-
<p class="text-body-2 mr-3 font-weight-bold text-center" data-test="tags-header">
68-
Tags
49+
<v-col
50+
v-for="header in headers"
51+
:key="header.label"
52+
>
53+
<p
54+
class="text-body-2 mb-2 font-(weight-bold) text-center"
55+
:data-test="`${normalizeLabel(header.label)}-header`"
56+
>
57+
{{ header.label }}
6958
</p>
7059
</v-col>
7160
</v-row>
72-
<QuickConnectionList ref="list" />
61+
62+
<QuickConnectionList ref="listRef" />
7363
</v-card-text>
64+
7465
<v-card-actions>
7566
<v-row class="ml-2">
7667
<v-col>
7768
<p class="text-body-2 mb-0 font-weight-bold text-grey-darken-1">
78-
<v-icon color="#7284D0" data-test="connect-icon">mdi-arrow-u-left-bottom</v-icon>
79-
To connect
69+
<v-icon color="#7284D0" data-test="connect-icon">mdi-arrow-u-left-bottom</v-icon> To connect
8070
</p>
8171
</v-col>
8272
<v-col>
8373
<p class="text-body-2 mb-0 font-weight-bold text-grey-darken-1">
8474
<v-icon color="#7284D0" data-test="navigate-up-icon">mdi-arrow-up</v-icon>
85-
<v-icon color="#7284D0" data-test="navigate-down-icon">mdi-arrow-down</v-icon>
86-
To navigate
75+
<v-icon color="#7284D0" data-test="navigate-down-icon">mdi-arrow-down</v-icon> To navigate
8776
</p>
8877
</v-col>
8978
<v-col>
90-
<p
91-
class="text-body-2 font-weight-bold text-grey-darken-1"
92-
data-test="copy-sshid-instructions"
93-
>
79+
<p class="text-body-2 font-weight-bold text-grey-darken-1" data-test="copy-sshid-instructions">
9480
Press "Ctrl + C" to copy SSHID
9581
</p>
9682
</v-col>
9783
</v-row>
98-
<v-btn variant="text" data-test="close-btn" @click="dialog = !dialog">
99-
Close
100-
</v-btn>
84+
85+
<v-btn variant="text" data-test="close-btn" @click="dialog = false">Close</v-btn>
10186
</v-card-actions>
10287
</v-card>
10388
</v-dialog>
10489
</div>
10590
</template>
10691

10792
<script setup lang="ts">
108-
// eslint-disable-next-line import/no-extraneous-dependencies
93+
import { ref, watch, onUnmounted } from "vue";
10994
import { useMagicKeys } from "@vueuse/core";
110-
import { watch, ref, onUnmounted } from "vue";
11195
import axios, { AxiosError } from "axios";
11296
import QuickConnectionList from "./QuickConnectionList.vue";
11397
import { useStore } from "@/store";
11498
import handleError from "@/utils/handleError";
11599
116-
const list = ref<InstanceType<typeof QuickConnectionList>>();
117100
const dialog = ref(false);
118-
const store = useStore();
119101
const filter = ref("");
120-
const show = ref(false);
102+
const listRef = ref<InstanceType<typeof QuickConnectionList> | null>(null);
103+
const store = useStore();
104+
105+
const headers = [
106+
{ label: "Hostname" },
107+
{ label: "Operating System" },
108+
{ label: "SSHID" },
109+
{ label: "Tags" },
110+
];
111+
112+
const normalizeLabel = (label: string) => label.toLowerCase().replace(/\s+/g, "-");
113+
114+
useMagicKeys({
115+
passive: false,
116+
onEventFired(event) {
117+
if (event.ctrlKey && event.key.toLowerCase() === "k" && event.type === "keydown") {
118+
event.preventDefault();
119+
dialog.value = !dialog.value;
120+
} else if ((event.key === "ArrowDown" || event.key === "ArrowUp") && event.type === "keydown") {
121+
event.preventDefault();
122+
listRef.value?.rootEl?.focus?.();
123+
}
124+
},
125+
});
121126
122127
const searchDevices = () => {
123128
let encodedFilter = "";
124129
125-
if (filter.value) {
126-
const filterToEncodeBase64 = [
130+
if (filter.value.trim()) {
131+
const filterObj = [
127132
{
128133
type: "property",
129134
params: { name: "name", operator: "contains", value: filter.value },
130135
},
131136
];
132-
encodedFilter = btoa(JSON.stringify(filterToEncodeBase64));
137+
encodedFilter = btoa(JSON.stringify(filterObj));
133138
}
134139
135-
if (dialog.value === false) {
140+
if (!dialog.value) {
136141
encodedFilter = "";
137142
}
138143
139-
try {
140-
store.dispatch("devices/searchQuickConnection", {
141-
page: store.getters["devices/getPage"],
142-
perPage: store.getters["devices/getPerPage"],
143-
filter: encodedFilter,
144-
status: store.getters["devices/getStatus"],
145-
});
146-
} catch {
144+
store.dispatch("devices/searchQuickConnection", {
145+
page: store.getters["devices/getPage"],
146+
perPage: store.getters["devices/getPerPage"],
147+
filter: encodedFilter,
148+
status: store.getters["devices/getStatus"],
149+
}).catch(() => {
147150
store.dispatch("snackbar/showSnackbarErrorDefault");
148-
}
151+
});
149152
};
150153
151-
watch(dialog, async (value) => {
152-
if (!value) return;
154+
watch(dialog, async (isOpen) => {
155+
if (!isOpen) return;
153156
154157
try {
155158
await store.dispatch("stats/get");
156-
show.value = true;
157-
} catch (error: unknown) {
158-
const axiosError = error as AxiosError;
159-
switch (axios.isAxiosError(error)) {
160-
case axiosError.response?.status === 403: {
161-
store.dispatch("snackbar/showSnackbarErrorAssociation");
162-
break; }
163-
default: store.dispatch("snackbar/showSnackbarErrorDefault");
159+
} catch (err: unknown) {
160+
const error = err as AxiosError;
161+
if (axios.isAxiosError(error) && error.response?.status === 403) {
162+
store.dispatch("snackbar/showSnackbarErrorAssociation");
163+
} else {
164+
store.dispatch("snackbar/showSnackbarErrorDefault");
164165
}
165166
handleError(error);
166167
}
167168
});
168169
169-
onUnmounted(async () => {
170-
await store.dispatch("devices/setFilter", "");
171-
});
172-
173-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
174-
const keyboardMacros = useMagicKeys({
175-
passive: false,
176-
onEventFired(e) {
177-
if (e.ctrlKey && e.key === "k" && e.type === "keydown") {
178-
e.preventDefault();
179-
dialog.value = !dialog.value;
180-
} else if ((e.key === "ArrowDown" || e.key === "ArrowUp") && e.type === "keydown") {
181-
e.preventDefault();
182-
list.value?.rootEl?.focus();
183-
}
184-
},
170+
onUnmounted(() => {
171+
store.dispatch("devices/setFilter", "");
185172
});
186173
</script>
187174

188-
<style lang="scss" scoped>
175+
<style scoped lang="scss">
189176
.code {
190177
font-family: monospace;
191178
font-size: 85%;

ui/src/components/QuickConnection/QuickConnectionList.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</v-card-title>
1111
<v-row>
1212
<v-col class="text-center d-flex justify-center pa-5">
13-
<p data-test="no-online-devices-message">No online device was found!</p>
13+
<p data-test="no-online-devices-message">There are currently no devices online.</p>
1414
</v-col>
1515
</v-row>
1616
</v-card>

ui/tests/components/QuickConnection/QuickConnection.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ describe("Quick Connection", () => {
131131

132132
expect(dialog.find('[data-test="search-text"]').exists()).toBe(true);
133133
expect(dialog.find('[data-test="hostname-header"]').exists()).toBe(true);
134-
expect(dialog.find('[data-test="os-header"]').exists()).toBe(true);
134+
expect(dialog.find('[data-test="operating-system-header"]').exists()).toBe(true);
135135
expect(dialog.find('[data-test="sshid-header"]').exists()).toBe(true);
136136
expect(dialog.find('[data-test="tags-header"]').exists()).toBe(true);
137137
expect(dialog.find('[data-test="connect-icon"]').exists()).toBe(true);

0 commit comments

Comments
 (0)