|
1 |
| -import { invoke, listen } from '$lib/backend/ipc'; |
2 |
| -import { RemoteFile } from '$lib/files/file'; |
3 |
| -import { plainToInstance } from 'class-transformer'; |
4 |
| -import { derived, writable } from 'svelte/store'; |
| 1 | +import { hasTauriExtra } from '$lib/state/backendQuery'; |
| 2 | +import { invalidatesList, providesList, ReduxTag } from '$lib/state/tags'; |
5 | 3 | import type { ConflictEntryPresence } from '$lib/conflictEntryPresence';
|
6 |
| -import type { StackService } from '$lib/stacks/stackService.svelte'; |
| 4 | +import type { TreeChange } from '$lib/hunks/change'; |
| 5 | +import type { ClientState } from '$lib/state/clientState.svelte'; |
7 | 6 |
|
8 | 7 | export interface EditModeMetadata {
|
9 | 8 | commitOid: string;
|
@@ -33,79 +32,120 @@ interface HeadAndMode {
|
33 | 32 | }
|
34 | 33 |
|
35 | 34 | export class ModeService {
|
36 |
| - private headAndMode = writable<HeadAndMode>({}, (set) => { |
37 |
| - this.refresh(); |
| 35 | + private api: ReturnType<typeof injectEndpoints>; |
38 | 36 |
|
39 |
| - const unsubscribe = subscribeToHead(this.projectId, (headAndMode) => { |
40 |
| - set(headAndMode); |
41 |
| - }); |
42 |
| - |
43 |
| - return unsubscribe; |
44 |
| - }); |
45 |
| - |
46 |
| - readonly head = derived(this.headAndMode, ({ head }) => head); |
47 |
| - readonly mode = derived(this.headAndMode, ({ operatingMode }) => operatingMode); |
48 |
| - |
49 |
| - constructor( |
50 |
| - private projectId: string, |
51 |
| - private readonly stackService: StackService |
52 |
| - ) {} |
53 |
| - |
54 |
| - private async refresh() { |
55 |
| - const head = await invoke<string>('git_head', { projectId: this.projectId }); |
56 |
| - const operatingMode = await invoke<Mode>('operating_mode', { projectId: this.projectId }); |
57 |
| - |
58 |
| - this.headAndMode.set({ head, operatingMode }); |
| 37 | + constructor(state: ClientState['backendApi']) { |
| 38 | + this.api = injectEndpoints(state); |
59 | 39 | }
|
60 | 40 |
|
61 |
| - async enterEditMode(commitId: string, stackId: string) { |
62 |
| - this.stackService.enterEditMode({ |
63 |
| - projectId: this.projectId, |
64 |
| - commitId, |
65 |
| - stackId |
66 |
| - }); |
67 |
| - await this.awaitMode('Edit'); |
| 41 | + get enterEditMode() { |
| 42 | + return this.api.endpoints.enterEditMode.mutate; |
68 | 43 | }
|
69 | 44 |
|
70 |
| - async abortEditAndReturnToWorkspace() { |
71 |
| - await this.stackService.abortEditAndReturnToWorkspace({ |
72 |
| - projectId: this.projectId |
73 |
| - }); |
74 |
| - await this.awaitMode('OpenWorkspace'); |
| 45 | + get abortEditAndReturnToWorkspace() { |
| 46 | + return this.api.endpoints.abortEditAndReturnToWorkspace.mutate; |
75 | 47 | }
|
76 | 48 |
|
77 |
| - async saveEditAndReturnToWorkspace() { |
78 |
| - await this.stackService.saveEditAndReturnToWorkspace({ |
79 |
| - projectId: this.projectId |
80 |
| - }); |
81 |
| - await this.awaitMode('OpenWorkspace'); |
| 49 | + get saveEditAndReturnToWorkspace() { |
| 50 | + return this.api.endpoints.saveEditAndReturnToWorkspace.mutate; |
82 | 51 | }
|
83 | 52 |
|
84 |
| - async getInitialIndexState() { |
85 |
| - const rawOutput = await invoke<unknown[][]>('edit_initial_index_state', { |
86 |
| - projectId: this.projectId |
87 |
| - }); |
88 |
| - |
89 |
| - return rawOutput.map((entry) => { |
90 |
| - return [plainToInstance(RemoteFile, entry[0]), entry[1] as ConflictEntryPresence | undefined]; |
91 |
| - }) as [RemoteFile, ConflictEntryPresence | undefined][]; |
| 53 | + get initialEditModeState() { |
| 54 | + return this.api.endpoints.initialEditModeState.useQuery; |
92 | 55 | }
|
93 | 56 |
|
94 |
| - async awaitMode(mode: Mode['type']): Promise<void> { |
95 |
| - return await new Promise((resolve) => { |
96 |
| - const unsubscribe = this.mode.subscribe((operatingMode) => { |
97 |
| - if (operatingMode && operatingMode?.type === mode) { |
98 |
| - resolve(); |
| 57 | + get mode() { |
| 58 | + return this.api.endpoints.mode.useQuery; |
| 59 | + } |
99 | 60 |
|
100 |
| - setTimeout(() => { |
101 |
| - unsubscribe(); |
102 |
| - }, 0); |
103 |
| - } |
104 |
| - }); |
105 |
| - }); |
| 61 | + get head() { |
| 62 | + return this.api.endpoints.mode.useQuery; |
106 | 63 | }
|
107 | 64 | }
|
108 | 65 |
|
109 |
| -function subscribeToHead(projectId: string, callback: (headAndMode: HeadAndMode) => void) { |
110 |
| - return listen<HeadAndMode>(`project://${projectId}/git/head`, (event) => callback(event.payload)); |
| 66 | +function injectEndpoints(api: ClientState['backendApi']) { |
| 67 | + return api.injectEndpoints({ |
| 68 | + endpoints: (build) => ({ |
| 69 | + enterEditMode: build.mutation<void, { projectId: string; commitId: string; stackId: string }>( |
| 70 | + { |
| 71 | + extraOptions: { command: 'enter_edit_mode' }, |
| 72 | + query: (args) => args, |
| 73 | + invalidatesTags: [ |
| 74 | + invalidatesList(ReduxTag.InitalEditListing), |
| 75 | + invalidatesList(ReduxTag.HeadMetadata) |
| 76 | + ] |
| 77 | + } |
| 78 | + ), |
| 79 | + abortEditAndReturnToWorkspace: build.mutation<void, { projectId: string }>({ |
| 80 | + extraOptions: { command: 'abort_edit_and_return_to_workspace' }, |
| 81 | + query: (args) => args, |
| 82 | + invalidatesTags: [ |
| 83 | + invalidatesList(ReduxTag.InitalEditListing), |
| 84 | + invalidatesList(ReduxTag.HeadMetadata) |
| 85 | + ] |
| 86 | + }), |
| 87 | + saveEditAndReturnToWorkspace: build.mutation<void, { projectId: string }>({ |
| 88 | + extraOptions: { command: 'save_edit_and_return_to_workspace' }, |
| 89 | + query: (args) => args, |
| 90 | + invalidatesTags: [ |
| 91 | + invalidatesList(ReduxTag.WorktreeChanges), |
| 92 | + invalidatesList(ReduxTag.StackDetails), |
| 93 | + invalidatesList(ReduxTag.InitalEditListing), |
| 94 | + invalidatesList(ReduxTag.HeadMetadata) |
| 95 | + ] |
| 96 | + }), |
| 97 | + initialEditModeState: build.query< |
| 98 | + [TreeChange, ConflictEntryPresence | undefined][], |
| 99 | + { projectId: string } |
| 100 | + >({ |
| 101 | + extraOptions: { command: 'edit_initial_index_state' }, |
| 102 | + query: (args) => args, |
| 103 | + providesTags: [providesList(ReduxTag.InitalEditListing)] |
| 104 | + }), |
| 105 | + mode: build.query<Mode, { projectId: string }>({ |
| 106 | + extraOptions: { command: 'operating_mode' }, |
| 107 | + query: (args) => args, |
| 108 | + providesTags: [providesList(ReduxTag.HeadMetadata)], |
| 109 | + async onCacheEntryAdded(arg, lifecycleApi) { |
| 110 | + if (!hasTauriExtra(lifecycleApi.extra)) { |
| 111 | + throw new Error('Redux dependency Tauri not found!'); |
| 112 | + } |
| 113 | + await lifecycleApi.cacheDataLoaded; |
| 114 | + const unsubscribe = lifecycleApi.extra.tauri.listen<HeadAndMode>( |
| 115 | + `project://${arg.projectId}/head`, |
| 116 | + (event) => { |
| 117 | + lifecycleApi.updateCachedData(() => event.payload.operatingMode); |
| 118 | + lifecycleApi.dispatch( |
| 119 | + api.util.invalidateTags([invalidatesList(ReduxTag.HeadMetadata)]) |
| 120 | + ); |
| 121 | + } |
| 122 | + ); |
| 123 | + await lifecycleApi.cacheEntryRemoved; |
| 124 | + unsubscribe(); |
| 125 | + } |
| 126 | + }), |
| 127 | + head: build.query<string, { projectId: string }>({ |
| 128 | + extraOptions: { command: 'git_head' }, |
| 129 | + query: (args) => args, |
| 130 | + providesTags: [providesList(ReduxTag.HeadMetadata)], |
| 131 | + async onCacheEntryAdded(arg, lifecycleApi) { |
| 132 | + if (!hasTauriExtra(lifecycleApi.extra)) { |
| 133 | + throw new Error('Redux dependency Tauri not found!'); |
| 134 | + } |
| 135 | + await lifecycleApi.cacheDataLoaded; |
| 136 | + const unsubscribe = lifecycleApi.extra.tauri.listen<HeadAndMode>( |
| 137 | + `project://${arg.projectId}/head`, |
| 138 | + (event) => { |
| 139 | + lifecycleApi.updateCachedData(() => event.payload.head); |
| 140 | + lifecycleApi.dispatch( |
| 141 | + api.util.invalidateTags([invalidatesList(ReduxTag.HeadMetadata)]) |
| 142 | + ); |
| 143 | + } |
| 144 | + ); |
| 145 | + await lifecycleApi.cacheEntryRemoved; |
| 146 | + unsubscribe(); |
| 147 | + } |
| 148 | + }) |
| 149 | + }) |
| 150 | + }); |
111 | 151 | }
|
0 commit comments