Skip to content

Commit 58384d5

Browse files
committed
feat: Improve type safety of watched values
1 parent a491187 commit 58384d5

File tree

7 files changed

+33
-37
lines changed

7 files changed

+33
-37
lines changed

src/features/instance/applications/components/TextEditorView/index.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { useEditorView } from '@/features/instance/applications/hooks/useEditorV
77
import { useEffectedState } from '@/hooks/useEffectedState';
88
import { useInstanceBrowseManagePermission } from '@/hooks/usePermissions';
99
import { currySetWatchedValue, useSetWatchedValue } from '@/hooks/useWatchedValue';
10-
import { WatchedValueKeys } from '@/lib/storage/watchedValueKeys';
1110
import { parseFileExtension } from '@/lib/string/parseFileExtension';
1211
import { Editor, EditorProps, OnMount } from '@monaco-editor/react';
1312
import { useParams } from '@tanstack/react-router';
@@ -98,19 +97,19 @@ export function TextEditorView() {
9897
id: 'new-file',
9998
label: 'New File',
10099
keybindings: [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KeyN],
101-
run: currySetWatchedValue(WatchedValueKeys.ShowAddDirectoryOrFileModalType, 'file'),
100+
run: currySetWatchedValue('ShowAddDirectoryOrFileModalType', 'file'),
102101
}),
103102
editor.addAction({
104103
id: 'rename-file',
105104
label: 'Rename File',
106105
keybindings: [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KeyR],
107-
run: currySetWatchedValue(WatchedValueKeys.ShowRenameFileModal, true),
106+
run: currySetWatchedValue('ShowRenameFileModal', true),
108107
}),
109108
editor.addAction({
110109
id: 'new-directory',
111110
label: 'New Directory',
112111
keybindings: [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyN],
113-
run: currySetWatchedValue(WatchedValueKeys.ShowAddDirectoryOrFileModalType, 'directory'),
112+
run: currySetWatchedValue('ShowAddDirectoryOrFileModalType', 'directory'),
114113
}),
115114
editor.addAction({
116115
id: 'save-file',
@@ -126,7 +125,7 @@ export function TextEditorView() {
126125
editor.addAction({
127126
id: 'delete-file',
128127
label: 'Delete File',
129-
run: currySetWatchedValue(WatchedValueKeys.ShowDeleteDirectoryOrFileModal, true),
128+
run: currySetWatchedValue('ShowDeleteDirectoryOrFileModal', true),
130129
}),
131130
];
132131
return () => {
@@ -136,11 +135,11 @@ export function TextEditorView() {
136135
};
137136
}, [mountedRef, canManageBrowseInstance, openedEntry, onSaveClick, onRevertChangesClicked]);
138137

139-
const onAddFileClick = useSetWatchedValue(WatchedValueKeys.ShowAddDirectoryOrFileModalType, 'file');
140-
const onAddDirectoryClick = useSetWatchedValue(WatchedValueKeys.ShowAddDirectoryOrFileModalType, 'directory');
141-
const onRenameClick = useSetWatchedValue(WatchedValueKeys.ShowRenameFileModal, true);
142-
const onDeleteClick = useSetWatchedValue(WatchedValueKeys.ShowDeleteDirectoryOrFileModal, true);
143-
const onRedeployClick = useSetWatchedValue(WatchedValueKeys.ShowRedeployApplicationModal, true);
138+
const onAddFileClick = useSetWatchedValue('ShowAddDirectoryOrFileModalType', 'file');
139+
const onAddDirectoryClick = useSetWatchedValue('ShowAddDirectoryOrFileModalType', 'directory');
140+
const onRenameClick = useSetWatchedValue('ShowRenameFileModal', true);
141+
const onDeleteClick = useSetWatchedValue('ShowDeleteDirectoryOrFileModal', true);
142+
const onRedeployClick = useSetWatchedValue('ShowRedeployApplicationModal', true);
144143

145144
if (!openedEntry) {
146145
return null;

src/features/instance/applications/modals/AddDirectoryOrFileModal.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@ import { useEditorView } from '@/features/instance/applications/hooks/useEditorV
2020
import { useSetComponentFile } from '@/features/instance/operations/mutations/setComponentFile';
2121
import { useSetWatchedValue, useWatchedValue } from '@/hooks/useWatchedValue';
2222
import { excludeFalsy } from '@/lib/arrays/excludeFalsy';
23-
import { WatchedValueKeys } from '@/lib/storage/watchedValueKeys';
2423
import { zodResolver } from '@hookform/resolvers/zod';
2524
import { Ban, Plus } from 'lucide-react';
2625
import { useCallback } from 'react';
2726
import { useForm } from 'react-hook-form';
2827
import z from 'zod';
2928

3029
export function AddDirectoryOrFileModal() {
31-
type ModalType = 'directory' | 'file' | false;
32-
const type = useWatchedValue<ModalType>(WatchedValueKeys.ShowAddDirectoryOrFileModalType, false);
33-
const hideModal = useSetWatchedValue<ModalType>(WatchedValueKeys.ShowAddDirectoryOrFileModalType, false);
30+
const type = useWatchedValue('ShowAddDirectoryOrFileModalType', false);
31+
const hideModal = useSetWatchedValue('ShowAddDirectoryOrFileModalType', false);
3432

3533
const { openedEntry, reloadRootEntries, setFocusedItem, setSelectedItems, setExpandedItems } = useEditorView();
3634
const instanceParams = useInstanceClientIdParams();

src/features/instance/applications/modals/DeleteDirectoryOrFileModal.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ import { isDirectory } from '@/features/instance/applications/context/isDirector
55
import { useEditorView } from '@/features/instance/applications/hooks/useEditorView';
66
import { useDropComponent } from '@/features/instance/operations/mutations/dropComponent';
77
import { setWatchedValue, useSetWatchedValue, useWatchedValue } from '@/hooks/useWatchedValue';
8-
import { WatchedValueKeys } from '@/lib/storage/watchedValueKeys';
98
import { Ban, Trash } from 'lucide-react';
109
import { MouseEvent, useCallback } from 'react';
1110

1211
export function DeleteDirectoryOrFileModal() {
13-
const isModalOpen = useWatchedValue(WatchedValueKeys.ShowDeleteDirectoryOrFileModal, false);
12+
const isModalOpen = useWatchedValue('ShowDeleteDirectoryOrFileModal', false);
1413

1514
const instanceParams = useInstanceClientIdParams();
1615
const { openedEntry, reloadRootEntries, setFocusedItem, setSelectedItems } = useEditorView();
@@ -33,7 +32,7 @@ export function DeleteDirectoryOrFileModal() {
3332
},
3433
{
3534
onSuccess: () => {
36-
setWatchedValue(WatchedValueKeys.ShowDeleteDirectoryOrFileModal, false);
35+
setWatchedValue('ShowDeleteDirectoryOrFileModal', false);
3736
const itemToFocus = !openedEntry.package && openedEntry.path.split('/').slice(0, -1).join('/');
3837
setFocusedItem(itemToFocus || undefined);
3938
setSelectedItems(itemToFocus ? [itemToFocus] : []);
@@ -48,7 +47,7 @@ export function DeleteDirectoryOrFileModal() {
4847
handleDeleteFolderOrFile();
4948
}, [handleDeleteFolderOrFile]);
5049

51-
const closeModal = useSetWatchedValue(WatchedValueKeys.ShowDeleteDirectoryOrFileModal, false);
50+
const closeModal = useSetWatchedValue('ShowDeleteDirectoryOrFileModal', false);
5251

5352
return (
5453
<Dialog onOpenChange={closeModal} open={isModalOpen}>

src/features/instance/applications/modals/RedeployApplicationModal.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@ import { useInstanceClientIdParams } from '@/config/useInstanceClient';
1111
import { useEditorView } from '@/features/instance/applications/hooks/useEditorView';
1212
import { useDeployComponentMutation } from '@/features/instance/operations/mutations/deployComponent';
1313
import { setWatchedValue, useWatchedValue } from '@/hooks/useWatchedValue';
14-
import { WatchedValueKeys } from '@/lib/storage/watchedValueKeys';
1514
import { useQueryClient } from '@tanstack/react-query';
1615
import { Ban, RefreshCwIcon } from 'lucide-react';
1716
import { FormEvent, useCallback } from 'react';
1817
import { useForm } from 'react-hook-form';
1918
import { toast } from 'sonner';
2019

2120
export function RedeployApplicationModal() {
22-
const isModalOpen = useWatchedValue(WatchedValueKeys.ShowRedeployApplicationModal, false);
21+
const isModalOpen = useWatchedValue('ShowRedeployApplicationModal', false);
2322

2423
const queryClient = useQueryClient();
2524
const instanceParams = useInstanceClientIdParams();
@@ -52,7 +51,7 @@ export function RedeployApplicationModal() {
5251
queryKey: [instanceParams.entityId, 'get_components'],
5352
refetchType: 'active',
5453
});
55-
setWatchedValue(WatchedValueKeys.ShowRedeployApplicationModal, false);
54+
setWatchedValue('ShowRedeployApplicationModal', false);
5655
},
5756
onError: () => {
5857
openedEntry.package = originalPackageUrl;
@@ -76,7 +75,7 @@ export function RedeployApplicationModal() {
7675
};
7776

7877
const modalClosed = useCallback(() => {
79-
setWatchedValue(WatchedValueKeys.ShowRedeployApplicationModal, false);
78+
setWatchedValue('ShowRedeployApplicationModal', false);
8079
methods.reset({ applicationUrl: packageUrl });
8180
}, [isModalOpen, methods]);
8281

src/features/instance/applications/modals/RenameFileModal.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ import { Input } from '@/components/ui/input';
1717
import { useEditorView } from '@/features/instance/applications/hooks/useEditorView';
1818
import { useRenameFile } from '@/features/instance/applications/hooks/useRenameFile';
1919
import { useSetWatchedValue, useWatchedValue } from '@/hooks/useWatchedValue';
20-
import { WatchedValueKeys } from '@/lib/storage/watchedValueKeys';
2120
import { zodResolver } from '@hookform/resolvers/zod';
2221
import { Ban, PencilIcon } from 'lucide-react';
2322
import { useCallback, useEffect, useState } from 'react';
2423
import { useForm } from 'react-hook-form';
2524
import z from 'zod';
2625

2726
export function RenameFileModal() {
28-
const isModalOpen = useWatchedValue(WatchedValueKeys.ShowRenameFileModal, false);
29-
const hideModal = useSetWatchedValue(WatchedValueKeys.ShowRenameFileModal, false);
27+
const isModalOpen = useWatchedValue('ShowRenameFileModal', false);
28+
const hideModal = useSetWatchedValue('ShowRenameFileModal', false);
3029

3130
const { openedEntry } = useEditorView();
3231
const RenameFileSchema = z.object({

src/hooks/useWatchedValue.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { WatchedValueKeys } from '@/lib/storage/watchedValueKeys';
1+
import { WatchedValueKeys, WatchedValuesTypeMap } from '@/lib/storage/watchedValueKeys';
22
import { useCallback, useEffect, useState } from 'react';
33

44
const listenersMap: Record<string, Array<(newValue: unknown) => void>> = {};
55

6-
export function useWatchedValue<T>(name: WatchedValueKeys): T | undefined
7-
export function useWatchedValue<T>(name: WatchedValueKeys, defaultValue: T): T
8-
export function useWatchedValue<T>(name: WatchedValueKeys, defaultValue?: T): T | undefined {
6+
export function useWatchedValue<K extends keyof WatchedValuesTypeMap, T extends WatchedValuesTypeMap[K]>(name: K): T | undefined
7+
export function useWatchedValue<K extends keyof WatchedValuesTypeMap, T extends WatchedValuesTypeMap[K], D extends T>(name: K, defaultValue: D): T
8+
export function useWatchedValue<K extends keyof WatchedValuesTypeMap, T extends WatchedValuesTypeMap[K], D extends T>(name: K, defaultValue?: D): T | undefined {
99
const [value, setValue] = useState<T | undefined>(defaultValue);
1010

1111
useEffect(() => {
@@ -28,7 +28,7 @@ export function useWatchedValue<T>(name: WatchedValueKeys, defaultValue?: T): T
2828
return value;
2929
}
3030

31-
export function setWatchedValue<T>(name: WatchedValueKeys, value: T): void {
31+
export function setWatchedValue<K extends keyof WatchedValuesTypeMap, T extends WatchedValuesTypeMap[K]>(name: WatchedValueKeys, value: T): void {
3232
const listeners = listenersMap[name] as Array<(newValue: T) => void>;
3333
if (listeners) {
3434
for (const listener of listeners) {
@@ -37,13 +37,13 @@ export function setWatchedValue<T>(name: WatchedValueKeys, value: T): void {
3737
}
3838
}
3939

40-
export function currySetWatchedValue<T>(name: WatchedValueKeys, value: T): () => void {
40+
export function currySetWatchedValue<K extends keyof WatchedValuesTypeMap, T extends WatchedValuesTypeMap[K]>(name: WatchedValueKeys, value: T): () => void {
4141
return () => {
4242
setWatchedValue(name, value);
4343
};
4444
}
4545

46-
export function useSetWatchedValue<T>(name: WatchedValueKeys, value: T): () => void {
46+
export function useSetWatchedValue<K extends keyof WatchedValuesTypeMap, T extends WatchedValuesTypeMap[K]>(name: WatchedValueKeys, value: T): () => void {
4747
return useCallback(() => {
4848
setWatchedValue(name, value);
4949
}, [name, value]);
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
export const enum WatchedValueKeys {
2-
ShowAddDirectoryOrFileModalType = 'ShowAddDirectoryOrFileModalType',
3-
ShowDeleteDirectoryOrFileModal = 'ShowDeleteDirectoryOrFileModal',
4-
ShowRedeployApplicationModal = 'ShowRedeployApplicationModal',
5-
ShowRenameFileModal = 'ShowRenameFileModal',
1+
export interface WatchedValuesTypeMap {
2+
ShowAddDirectoryOrFileModalType: 'file' | 'directory' | false;
3+
ShowDeleteDirectoryOrFileModal: boolean;
4+
ShowRedeployApplicationModal: boolean;
5+
ShowRenameFileModal: boolean;
66
}
7+
8+
export type WatchedValueKeys = keyof WatchedValuesTypeMap;

0 commit comments

Comments
 (0)