making strides in the device and link domain setup
This commit is contained in:
88
apps/main/src/lib/domains/device/device.remote.ts
Normal file
88
apps/main/src/lib/domains/device/device.remote.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { getDeviceController } from "@pkg/logic/domains/device/controller";
|
||||
import { createDeviceSchema, updateDeviceSchema } from "@pkg/logic/domains/device/data";
|
||||
import { getFlowExecCtxForRemoteFuncs, unauthorized } from "$lib/core/server.utils";
|
||||
import { command, getRequestEvent, query } from "$app/server";
|
||||
import * as v from "valibot";
|
||||
|
||||
const dc = getDeviceController();
|
||||
|
||||
export const listDevicesSQ = query(async () => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await dc.list(fctx);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
});
|
||||
|
||||
export const getDeviceByIdSQ = query(
|
||||
v.object({ id: v.number() }),
|
||||
async (input) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await dc.getById(fctx, input.id);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const createDeviceSC = command(createDeviceSchema, async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await dc.create(fctx, payload);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
});
|
||||
|
||||
export const updateDeviceSC = command(
|
||||
v.object({ id: v.number(), data: updateDeviceSchema }),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await dc.update(fctx, payload.id, payload.data);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const deleteDeviceSC = command(
|
||||
v.object({ id: v.number() }),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await dc.delete(fctx, payload.id);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const setDeviceStatusSC = command(
|
||||
v.object({
|
||||
id: v.number(),
|
||||
status: v.picklist(["online", "offline", "busy", "error"]),
|
||||
}),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await dc.setStatus(fctx, payload.id, payload.status as any);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
152
apps/main/src/lib/domains/device/device.vm.svelte.ts
Normal file
152
apps/main/src/lib/domains/device/device.vm.svelte.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import {
|
||||
listDevicesSQ,
|
||||
createDeviceSC,
|
||||
deleteDeviceSC,
|
||||
setDeviceStatusSC,
|
||||
} from "./device.remote";
|
||||
import { toast } from "svelte-sonner";
|
||||
|
||||
type Device = {
|
||||
id: number;
|
||||
title: string;
|
||||
version: string;
|
||||
status: string;
|
||||
isActive: boolean;
|
||||
containerId: string | null;
|
||||
host: string;
|
||||
wsPort: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
|
||||
type CreateDeviceInput = {
|
||||
title: string;
|
||||
version: string;
|
||||
host: string;
|
||||
containerId?: string;
|
||||
wsPort?: string;
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
class DeviceViewModel {
|
||||
devices = $state<Device[]>([]);
|
||||
loading = $state(false);
|
||||
creating = $state(false);
|
||||
deletingId = $state<number | null>(null);
|
||||
showCreateDialog = $state(false);
|
||||
|
||||
async fetchDevices() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const result = await listDevicesSQ();
|
||||
if (result?.error || !result?.data) {
|
||||
toast.error(
|
||||
result?.error?.message || "Failed to fetch devices",
|
||||
{
|
||||
description:
|
||||
result?.error?.description || "Please try again",
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
this.devices = result.data as Device[];
|
||||
} catch (error) {
|
||||
toast.error("Failed to fetch devices", {
|
||||
description:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Please try again",
|
||||
});
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async createDevice(data: CreateDeviceInput): Promise<boolean> {
|
||||
this.creating = true;
|
||||
try {
|
||||
const result = await createDeviceSC(data);
|
||||
if (result?.error) {
|
||||
toast.error(
|
||||
result.error.message || "Failed to create device",
|
||||
{
|
||||
description:
|
||||
result.error.description || "Please try again",
|
||||
},
|
||||
);
|
||||
return false;
|
||||
}
|
||||
toast.success("Device created");
|
||||
this.showCreateDialog = false;
|
||||
await this.fetchDevices();
|
||||
return true;
|
||||
} catch (error) {
|
||||
toast.error("Failed to create device", {
|
||||
description:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Please try again",
|
||||
});
|
||||
return false;
|
||||
} finally {
|
||||
this.creating = false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteDevice(id: number) {
|
||||
this.deletingId = id;
|
||||
try {
|
||||
const result = await deleteDeviceSC({ id });
|
||||
if (result?.error) {
|
||||
toast.error(
|
||||
result.error.message || "Failed to delete device",
|
||||
{
|
||||
description:
|
||||
result.error.description || "Please try again",
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
toast.success("Device deleted");
|
||||
await this.fetchDevices();
|
||||
} catch (error) {
|
||||
toast.error("Failed to delete device", {
|
||||
description:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Please try again",
|
||||
});
|
||||
} finally {
|
||||
this.deletingId = null;
|
||||
}
|
||||
}
|
||||
|
||||
async setStatus(id: number, status: string) {
|
||||
try {
|
||||
const result = await setDeviceStatusSC({
|
||||
id,
|
||||
status: status as any,
|
||||
});
|
||||
if (result?.error) {
|
||||
toast.error(
|
||||
result.error.message || "Failed to update status",
|
||||
{
|
||||
description:
|
||||
result.error.description || "Please try again",
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
await this.fetchDevices();
|
||||
} catch (error) {
|
||||
toast.error("Failed to update status", {
|
||||
description:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Please try again",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const deviceVM = new DeviceViewModel();
|
||||
108
apps/main/src/lib/domains/link/link.remote.ts
Normal file
108
apps/main/src/lib/domains/link/link.remote.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { getLinkController } from "@pkg/logic/domains/link/controller";
|
||||
import { updateLinkSchema } from "@pkg/logic/domains/link/data";
|
||||
import { getFlowExecCtxForRemoteFuncs, unauthorized } from "$lib/core/server.utils";
|
||||
import { command, getRequestEvent, query } from "$app/server";
|
||||
import * as v from "valibot";
|
||||
|
||||
const lc = getLinkController();
|
||||
|
||||
export const listLinksSQ = query(async () => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.list(fctx);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
});
|
||||
|
||||
export const getLinkByIdSQ = query(
|
||||
v.object({ id: v.number() }),
|
||||
async (input) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.getById(fctx, input.id);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const createLinkSC = command(
|
||||
v.object({
|
||||
linkedDeviceId: v.optional(v.nullable(v.number())),
|
||||
expiresAt: v.optional(v.nullable(v.date())),
|
||||
}),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.create(fctx, payload);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const updateLinkSC = command(
|
||||
v.object({ id: v.number(), data: updateLinkSchema }),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.update(fctx, payload.id, payload.data);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const revokeLinkSC = command(
|
||||
v.object({ id: v.number() }),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.revoke(fctx, payload.id);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const deleteLinkSC = command(
|
||||
v.object({ id: v.number() }),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.delete(fctx, payload.id);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
|
||||
export const assignDeviceSC = command(
|
||||
v.object({
|
||||
id: v.number(),
|
||||
deviceId: v.nullable(v.number()),
|
||||
}),
|
||||
async (payload) => {
|
||||
const event = getRequestEvent();
|
||||
const fctx = await getFlowExecCtxForRemoteFuncs(event.locals);
|
||||
if (!fctx.userId) return unauthorized(fctx);
|
||||
|
||||
const res = await lc.assignDevice(fctx, payload.id, payload.deviceId);
|
||||
return res.isOk()
|
||||
? { data: res.value, error: null }
|
||||
: { data: null, error: res.error };
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user