mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-18 14:33:19 +00:00
b65daf6845
* feat: add notification suppression rules * fix: restore label routing and routing test mocks for suppression * fix: allow bell mute shortcuts for history-only notification categories Suppression rule validation used the routable category whitelist, which rejected history-only categories such as update_started that appear in the bell during stack updates. * feat: expand Mute Rules UX with compose-first entry points and activity badges * fix: add missing NodeContext mocks for notification suppression tests
108 lines
3.8 KiB
TypeScript
108 lines
3.8 KiB
TypeScript
import { useCallback, useMemo } from 'react';
|
|
import { useAuth } from '@/context/AuthContext';
|
|
import { useNodes } from '@/context/NodeContext';
|
|
import {
|
|
createMuteRuleWithToast,
|
|
stackMuteAllDraft,
|
|
stackMuteDeploySuccessDraft,
|
|
stackMuteMonitorDraft,
|
|
labelMuteAllDraft,
|
|
labelMuteExternalDraft,
|
|
labelMuteLowPriorityDraft,
|
|
nodeMuteAllDraft,
|
|
nodeMuteUpdatesDraft,
|
|
nodeMuteMonitorDraft,
|
|
type MuteRuleDraft,
|
|
} from '@/lib/muteRules';
|
|
|
|
export type OpenMuteRulesPrefill = (draft: MuteRuleDraft) => void;
|
|
|
|
export function useCanMuteNotifications(): boolean {
|
|
const { isAdmin } = useAuth();
|
|
const { hasCapability } = useNodes();
|
|
return isAdmin && hasCapability('notification-suppression');
|
|
}
|
|
|
|
export function useStackMuteActions(stackName: string, openMuteRulesWithPrefill: OpenMuteRulesPrefill) {
|
|
const { activeNode } = useNodes();
|
|
const canMute = useCanMuteNotifications();
|
|
const nodeId = activeNode?.id ?? null;
|
|
|
|
const muteAll = useCallback(() => {
|
|
void createMuteRuleWithToast(stackMuteAllDraft(stackName, nodeId));
|
|
}, [stackName, nodeId]);
|
|
|
|
const muteDeploySuccess = useCallback(() => {
|
|
void createMuteRuleWithToast(stackMuteDeploySuccessDraft(stackName, nodeId));
|
|
}, [stackName, nodeId]);
|
|
|
|
const muteMonitor = useCallback(() => {
|
|
void createMuteRuleWithToast(stackMuteMonitorDraft(stackName, nodeId));
|
|
}, [stackName, nodeId]);
|
|
|
|
const manage = useCallback(() => {
|
|
openMuteRulesWithPrefill(stackMuteAllDraft(stackName, nodeId));
|
|
}, [stackName, nodeId, openMuteRulesWithPrefill]);
|
|
|
|
return useMemo(
|
|
() => ({ canMute, muteAll, muteDeploySuccess, muteMonitor, manage }),
|
|
[canMute, muteAll, muteDeploySuccess, muteMonitor, manage],
|
|
);
|
|
}
|
|
|
|
export function useLabelMuteActions(
|
|
labelId: number,
|
|
labelName: string,
|
|
openMuteRulesWithPrefill: OpenMuteRulesPrefill,
|
|
) {
|
|
const { activeNode } = useNodes();
|
|
const canMute = useCanMuteNotifications();
|
|
const nodeId = activeNode?.id ?? null;
|
|
|
|
const muteAll = useCallback(() => {
|
|
void createMuteRuleWithToast(labelMuteAllDraft(labelId, labelName, nodeId));
|
|
}, [labelId, labelName, nodeId]);
|
|
|
|
const muteExternal = useCallback(() => {
|
|
void createMuteRuleWithToast(labelMuteExternalDraft(labelId, labelName, nodeId));
|
|
}, [labelId, labelName, nodeId]);
|
|
|
|
const muteLowPriority = useCallback(() => {
|
|
void createMuteRuleWithToast(labelMuteLowPriorityDraft(labelId, labelName, nodeId));
|
|
}, [labelId, labelName, nodeId]);
|
|
|
|
const manage = useCallback(() => {
|
|
openMuteRulesWithPrefill(labelMuteAllDraft(labelId, labelName, nodeId));
|
|
}, [labelId, labelName, nodeId, openMuteRulesWithPrefill]);
|
|
|
|
return useMemo(
|
|
() => ({ canMute, muteAll, muteExternal, muteLowPriority, manage }),
|
|
[canMute, muteAll, muteExternal, muteLowPriority, manage],
|
|
);
|
|
}
|
|
|
|
export function useNodeMuteActions(nodeId: number, nodeName: string, openMuteRulesWithPrefill: OpenMuteRulesPrefill) {
|
|
const canMute = useCanMuteNotifications();
|
|
|
|
const muteAll = useCallback(() => {
|
|
void createMuteRuleWithToast(nodeMuteAllDraft(nodeId, nodeName));
|
|
}, [nodeId, nodeName]);
|
|
|
|
const muteUpdates = useCallback(() => {
|
|
void createMuteRuleWithToast(nodeMuteUpdatesDraft(nodeId, nodeName));
|
|
}, [nodeId, nodeName]);
|
|
|
|
const muteMonitor = useCallback(() => {
|
|
void createMuteRuleWithToast(nodeMuteMonitorDraft(nodeId, nodeName));
|
|
}, [nodeId, nodeName]);
|
|
|
|
const manage = useCallback(() => {
|
|
openMuteRulesWithPrefill(nodeMuteAllDraft(nodeId, nodeName));
|
|
}, [nodeId, nodeName, openMuteRulesWithPrefill]);
|
|
|
|
return useMemo(
|
|
() => ({ canMute, muteAll, muteUpdates, muteMonitor, manage }),
|
|
[canMute, muteAll, muteUpdates, muteMonitor, manage],
|
|
);
|
|
}
|