Skip to content

Commit

Permalink
feat: device management / confirm dialog for delete device
Browse files Browse the repository at this point in the history
  • Loading branch information
ChingCdesu committed Oct 11, 2023
1 parent 63ff645 commit 2a2d3cb
Show file tree
Hide file tree
Showing 11 changed files with 596 additions and 245 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "supernode-frontend",
"private": true,
"version": "1.0.0-alpha.8",
"version": "1.0.0-alpha.9",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down Expand Up @@ -31,6 +31,7 @@
"typescript": "^4.9.5",
"unocss": "^0.56.2",
"vite": "^4.4.9",
"vue-tsc": "^1.8.14"
"vue-tsc": "^1.8.14",
"type-fest": "4.4.0"
}
}
10 changes: 9 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

238 changes: 238 additions & 0 deletions src/components/common/DeviceEditModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
<script lang="ts" setup>
import { Community } from "@/api/v1/dtos/community";
import { Device } from "@/api/v1/dtos/devices";
import { computed, onMounted, ref } from "vue";
import { type PartialDeep } from "type-fest";
import {
NCard,
NForm,
NButton,
NSpace,
NInput,
NSelect,
NFormItem,
NText,
FormInst,
FormRules,
} from "naive-ui";
import { useI18n } from "vue-i18n";
import { listCommunities } from "@/api/v1/business/community";
import { generate_user_token } from "@/utils/crypto";
import { listUsers } from "@/api/v1/business/users";
import { User } from "@/api/v1/dtos/users";
const props = defineProps<{
community?: Community;
device?: Device;
withOwnerSelect?: boolean;
}>();
const emit = defineEmits<{
(e: "close"): void;
(e: "finished", community: Community, device: PartialDeep<Device>): void;
}>();
const { t } = useI18n();
const isNew = computed(() => !props.device);
const device = ref<PartialDeep<Device & { password: string }>>(
props.device ?? {}
);
const communities = ref<Community[]>([]);
const selectedCommunityId = ref<number | undefined>(props.community?.id);
const selectedCommunity = computed(() => {
return communities.value.find((c) => c.id === selectedCommunityId.value);
});
const communityOptions = computed(() => {
return communities.value.map((c) => ({
label: c.name,
value: c.id,
}));
});
const users = ref<User[]>([]);
const userOptions = computed(() => {
return users.value.map((u) => ({
label: u.name,
value: u.id,
}));
});
const formRef = ref<FormInst | undefined>();
const rules: FormRules = {
name: {
required: true,
message: t("message.common.required", {
field: t("message.devices.column.name"),
}),
trigger: "blur",
},
communityId: {
required: true,
type: "number",
message: t("message.common.required", {
field: t("message.common.community"),
}),
trigger: "blur",
validator: () => !!selectedCommunityId.value,
},
password: {
required: true,
message: t("message.common.required", {
field: t("message.devices.column.password"),
}),
trigger: "blur",
},
ownerId: {
required: props.withOwnerSelect,
type: "number",
message: t("message.common.required", {
field: t("message.devices.column.owner"),
}),
validator: () => !!device.value.owner?.id,
},
};
function handleSubmit() {
formRef.value?.validate((errors) => {
if (errors) {
return;
}
handleFinish();
});
}
async function handleFinish() {
device.value.publicKey = await generate_user_token(
device.value.name!,
device.value.password!
);
delete device.value.password;
emit("finished", selectedCommunity.value!, device.value);
}
async function getCommunities() {
let page = 1;
let stop = false;
const result: Community[] = [];
while (!stop) {
try {
const res = await listCommunities({ page, limit: 100 });
const arr = res.data.data?.data.filter((c) => c.encryption) ?? [];
result.push(...arr);
if (res.data.data?.meta.hasNextPage) {
page++;
} else {
stop = true;
}
} catch (e) {
console.error(e);
stop = true;
}
}
result.sort((a, b) => a.id - b.id);
communities.value = result;
}
async function getUsers() {
let page = 1;
let stop = false;
const result: User[] = [];
while (!stop) {
try {
const res = await listUsers({ page, limit: 100 });
const arr = res.data.data?.data ?? [];
result.push(...arr);
if (res.data.data?.meta.hasNextPage) {
page++;
} else {
stop = true;
}
} catch (e) {
console.error(e);
stop = true;
}
}
result.sort((a, b) => a.id - b.id);
users.value = result;
}
onMounted(async () => {
await getCommunities();
if (props.withOwnerSelect) {
await getUsers();
}
});
</script>

<template>
<NCard class="w-1/2">
<template #header>
<NText>
{{
isNew
? $t("message.editDeviceModal.addNewDevice")
: $t("message.editDeviceModal.editDevice")
}}
</NText>
</template>
<template #default>
<NForm
label-placement="left"
label-width="auto"
ref="formRef"
:model="device"
:rules="rules"
>
<NFormItem :label="t('message.common.community')" path="communityId">
<NSelect
filterable
:placeholder="t('message.newDevice.selectCommunity')"
:options="communityOptions"
v-model:value="selectedCommunityId"
/>
</NFormItem>
<NFormItem
v-if="props.withOwnerSelect"
:label="t('message.devices.column.owner')"
path="ownerId"
>
<NSelect
:default-value="device.owner?.id"
:options="userOptions"
:placeholder="t('message.devices.column.owner')"
@update:value="(value: number) => device.owner = users.find(u => u.id === value)!"
/>
</NFormItem>
<NFormItem :label="t('message.newDevice.deviceName')" path="name">
<NInput v-model:value="device.name" />
</NFormItem>
<NFormItem :label="t('message.newDevice.password')" path="password">
<NInput
type="password"
v-model:value="device.password"
show-password-on="click"
/>
</NFormItem>
</NForm>
</template>
<template #footer>
<NSpace align="center" justify="end">
<NButton type="primary" @click="handleSubmit">
{{
isNew ? $t("message.common.create") : $t("message.common.update")
}}
</NButton>
<NButton @click="emit('close')">
{{ $t("message.common.cancel") }}
</NButton>
</NSpace>
</template>
</NCard>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async function getCommunities() {
function handleEdit(community: Community) {}
function handleRemove(community: Community) {
dialog.warning({
dialog.error({
title: t("message.admin.community.remove.confirm"),
content: t("message.admin.community.remove.confirmTip"),
positiveText: t("message.common.confirm"),
Expand Down
Loading

0 comments on commit 2a2d3cb

Please sign in to comment.