M8-T18: add source and multi-commodity meter UI
This commit is contained in:
@@ -237,6 +237,13 @@ export type SummaryResponse = components['schemas']['SummaryResponse']
|
||||
export type DsmrLatestResponse = components['schemas']['DsmrLatestResponse']
|
||||
export type TibberTestResponse = components['schemas']['TibberTestResponse']
|
||||
export type TibberTestPriceSchema = components['schemas']['TibberTestPriceSchema']
|
||||
export type SourceProfileResponse = components['schemas']['SourceProfileResponse']
|
||||
export type MeterSourceResponse = components['schemas']['MeterSourceResponse']
|
||||
export type MeterSourceCreate = components['schemas']['MeterSourceCreate']
|
||||
export type MeterSourcePatch = components['schemas']['MeterSourcePatch']
|
||||
export type MeterSourceChannelResponse = components['schemas']['MeterSourceChannelResponse']
|
||||
export type BindingResponse = components['schemas']['BindingResponse']
|
||||
export type BindingCreate = components['schemas']['BindingCreate']
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Query: list all energy contracts
|
||||
@@ -470,8 +477,14 @@ export function useDeclareMeter() {
|
||||
return useMutation({
|
||||
mutationFn: (body: MeterDeclareRequest) =>
|
||||
apiClient.POST('/api/energy/meters', { body }),
|
||||
onSuccess: () => {
|
||||
onSuccess: (_data, variables) => {
|
||||
void qc.invalidateQueries({ queryKey: ['energy-meters'] })
|
||||
if (variables.source_channel_uuid) {
|
||||
void qc.invalidateQueries({ queryKey: ['energy-source-channels'] })
|
||||
void qc.invalidateQueries({ queryKey: ['energy-meter-bindings'] })
|
||||
void qc.invalidateQueries({ queryKey: ['energy-sources'] })
|
||||
void qc.invalidateQueries({ queryKey: ['expose-catalog'] })
|
||||
}
|
||||
// Invalidate cost-related queries: a new meter may trigger recompute server-side.
|
||||
void qc.invalidateQueries({ queryKey: ['energy-costs'] })
|
||||
void qc.invalidateQueries({ queryKey: ['energy-costs-summary'] })
|
||||
@@ -500,6 +513,39 @@ export function useUpdateMeter() {
|
||||
})
|
||||
}
|
||||
|
||||
// Source → channel → binding hooks. These deliberately use the generated
|
||||
// OpenAPI types; UI suggestions remain just suggestions until a user binds one.
|
||||
export function useSourceProfiles() {
|
||||
return useQuery({ queryKey: ['energy-source-profiles'], queryFn: async () => {
|
||||
const res = await apiClient.GET('/api/energy/source-profiles'); return res.data
|
||||
}, staleTime: 5 * 60 * 1000 })
|
||||
}
|
||||
export function useSources() {
|
||||
return useQuery({ queryKey: ['energy-sources'], queryFn: async () => {
|
||||
const res = await apiClient.GET('/api/energy/sources'); return res.data
|
||||
} })
|
||||
}
|
||||
export function useSource(uuid: string | null) {
|
||||
return useQuery({ queryKey: ['energy-source', uuid], enabled: !!uuid, queryFn: async () => {
|
||||
const res = await apiClient.GET('/api/energy/sources/{source_uuid}', { params: { path: { source_uuid: uuid! } } }); return res.data
|
||||
} })
|
||||
}
|
||||
function invalidateSourceQueries(qc: ReturnType<typeof useQueryClient>) {
|
||||
void qc.invalidateQueries({ queryKey: ['energy-sources'] }); void qc.invalidateQueries({ queryKey: ['energy-source'] });
|
||||
void qc.invalidateQueries({ queryKey: ['energy-source-channels'] }); void qc.invalidateQueries({ queryKey: ['energy-meters'] });
|
||||
void qc.invalidateQueries({ queryKey: ['energy-channel-readings'] }); void qc.invalidateQueries({ queryKey: ['energy-meter-bindings'] })
|
||||
void qc.invalidateQueries({ queryKey: ['expose-catalog'] })
|
||||
}
|
||||
export function useCreateSource() { const qc = useQueryClient(); return useMutation({ mutationFn: (body: MeterSourceCreate) => apiClient.POST('/api/energy/sources', { body }), onSuccess: () => invalidateSourceQueries(qc) }) }
|
||||
export function useUpdateSource() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ uuid, body }: { uuid: string; body: MeterSourcePatch }) => apiClient.PATCH('/api/energy/sources/{source_uuid}', { params: { path: { source_uuid: uuid } }, body }), onSuccess: () => invalidateSourceQueries(qc) }) }
|
||||
export function useDeleteSource() { const qc = useQueryClient(); return useMutation({ mutationFn: (uuid: string) => apiClient.DELETE('/api/energy/sources/{source_uuid}', { params: { path: { source_uuid: uuid } } }), onSuccess: () => invalidateSourceQueries(qc) }) }
|
||||
export function useDiscoverSource() { const qc = useQueryClient(); return useMutation({ mutationFn: (uuid: string) => apiClient.POST('/api/energy/sources/{source_uuid}/discover', { params: { path: { source_uuid: uuid } } }), onSuccess: () => invalidateSourceQueries(qc) }) }
|
||||
export function useSourceChannels(uuid: string | null) { return useQuery({ queryKey: ['energy-source-channels', uuid], enabled: !!uuid, queryFn: async () => { const res = await apiClient.GET('/api/energy/sources/{source_uuid}/channels', { params: { path: { source_uuid: uuid! } } }); return res.data } }) }
|
||||
export function useChannelReadings(sourceUuid: string | null, channelUuid: string | null) { return useQuery({ queryKey: ['energy-channel-readings', sourceUuid, channelUuid], enabled: !!sourceUuid && !!channelUuid, queryFn: async () => { const res = await apiClient.GET('/api/energy/sources/{source_uuid}/channels/{channel_uuid}/readings', { params: { path: { source_uuid: sourceUuid!, channel_uuid: channelUuid! }, query: { limit: 60 } } }); return res.data } }) }
|
||||
export function useMeterBindings(id: number | null) { return useQuery({ queryKey: ['energy-meter-bindings', id], enabled: id != null, queryFn: async () => { const res = await apiClient.GET('/api/energy/meters/{meter_id}/bindings', { params: { path: { meter_id: id! } } }); return res.data } }) }
|
||||
export function useCreateBinding() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ id, body }: { id: number; body: BindingCreate }) => apiClient.POST('/api/energy/meters/{meter_id}/bindings', { params: { path: { meter_id: id } }, body }), onSuccess: () => invalidateSourceQueries(qc) }) }
|
||||
export function useCloseBinding() { const qc = useQueryClient(); return useMutation({ mutationFn: ({ uuid, ended_at }: { uuid: string; ended_at: string }) => apiClient.PATCH('/api/energy/bindings/{binding_uuid}', { params: { path: { binding_uuid: uuid } }, body: { ended_at } }), onSuccess: () => invalidateSourceQueries(qc) }) }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Query: time-range readings for a device (window + limit — never full-table)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user