CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / integration (push) Successful in 50s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / Python tests (push) Successful in 1m44s
CI & Build / Build & push image (push) Successful in 36s
#4769 "Rulings are counted where someone will read them": milestone 444 step 4 wrote system_usage_events and nothing read it. - retrieval_telemetry gains a `system_usage` block: surfacings and opens by source, distinct counts, and `by_system` naming the areas most shown. There is deliberately no pull-through ratio, because rulings travel in full in the line and opens are the exception. - usage_for_systems (one GROUP BY) adds `usage` to the REST Systems list and detail, and to MCP get_system. MCP list_systems is unchanged. - The Systems UI shows a "rulings shown N×" chip. - rulings_pre_tool, rulings_write_path and mcp_get_system are now declared registry points; the registry guard covers their recorders. - The Systems store merges a PATCH reply instead of replacing the row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { ref } from "vue";
|
|
import { defineStore } from "pinia";
|
|
import * as api from "@/api/systems";
|
|
import type { System } from "@/api/systems";
|
|
import { useToastStore } from "@/stores/toast";
|
|
|
|
export const useSystemsStore = defineStore("systems", () => {
|
|
const systemsByProject = ref<Record<number, System[]>>({});
|
|
const loading = ref(false);
|
|
|
|
async function fetchSystems(projectId: number) {
|
|
loading.value = true;
|
|
try {
|
|
systemsByProject.value[projectId] = await api.listSystems(projectId);
|
|
} catch (e) {
|
|
useToastStore().show("Failed to load systems", "error");
|
|
throw e;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function createSystem(
|
|
projectId: number,
|
|
data: Parameters<typeof api.createSystem>[1],
|
|
) {
|
|
const system = await api.createSystem(projectId, data);
|
|
if (!systemsByProject.value[projectId]) systemsByProject.value[projectId] = [];
|
|
systemsByProject.value[projectId].push(system);
|
|
return system;
|
|
}
|
|
|
|
async function updateSystem(
|
|
projectId: number,
|
|
systemId: number,
|
|
data: Parameters<typeof api.updateSystem>[2],
|
|
) {
|
|
const system = await api.updateSystem(projectId, systemId, data);
|
|
const list = systemsByProject.value[projectId];
|
|
if (list) {
|
|
const idx = list.findIndex((s) => s.id === systemId);
|
|
// Merged, not replaced: the PATCH reply is the bare System, and the
|
|
// list's read-side decorations (issue count, rulings usage) would
|
|
// otherwise vanish from the row until the next reload.
|
|
if (idx >= 0) list[idx] = { ...list[idx], ...system };
|
|
}
|
|
return system;
|
|
}
|
|
|
|
async function archiveSystem(projectId: number, systemId: number) {
|
|
return updateSystem(projectId, systemId, { status: "archived" });
|
|
}
|
|
|
|
async function unarchiveSystem(projectId: number, systemId: number) {
|
|
return updateSystem(projectId, systemId, { status: "active" });
|
|
}
|
|
|
|
async function deleteSystem(projectId: number, systemId: number) {
|
|
await api.deleteSystem(projectId, systemId);
|
|
const list = systemsByProject.value[projectId];
|
|
if (list) {
|
|
systemsByProject.value[projectId] = list.filter((s) => s.id !== systemId);
|
|
}
|
|
}
|
|
|
|
return {
|
|
systemsByProject,
|
|
loading,
|
|
fetchSystems,
|
|
createSystem,
|
|
updateSystem,
|
|
archiveSystem,
|
|
unarchiveSystem,
|
|
deleteSystem,
|
|
};
|
|
});
|