-
Notifications
You must be signed in to change notification settings - Fork 559
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- uses RTK Query
- Loading branch information
Showing
6 changed files
with
137 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Tauri } from '$lib/backend/tauri'; | ||
import { createApi, type BaseQueryApi, type BaseQueryFn } from '@reduxjs/toolkit/query'; | ||
|
||
export const reduxApi = createApi({ | ||
reducerPath: 'api', | ||
tagTypes: ['Stacks'], | ||
baseQuery: tauriBaseQuery, | ||
endpoints: (_) => { | ||
return {}; | ||
} | ||
}); | ||
|
||
function tauriBaseQuery<T>( | ||
args: ApiArgs, | ||
api: BaseQueryApi | ||
): ReturnType<BaseQueryFn<ApiArgs, Promise<T>, TauriCommandError, object, object>> { | ||
if (!hasTauriExtra(api.extra)) { | ||
return { error: 'Redux dependency Tauri not found!' }; | ||
} | ||
try { | ||
return { data: api.extra.tauri.invoke(args.command, args.params) }; | ||
} catch (error: unknown) { | ||
return { error }; | ||
} | ||
} | ||
|
||
type ApiArgs = { | ||
command: string; | ||
params: Record<string, unknown>; | ||
}; | ||
|
||
type TauriCommandError = unknown; | ||
|
||
/** | ||
* Typeguard that makes `tauriBaseQuery` more concise. | ||
*/ | ||
function hasTauriExtra(extra: unknown): extra is { | ||
tauri: Tauri; | ||
} { | ||
return ( | ||
!!extra && | ||
typeof extra === 'object' && | ||
extra !== null && | ||
'tauri' in extra && | ||
extra.tauri instanceof Tauri | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,39 @@ | ||
import { branchReviewListingsReducer } from '@gitbutler/shared/branches/branchReviewListingsSlice'; | ||
import { branchesReducer } from '@gitbutler/shared/branches/branchesSlice'; | ||
import { latestBranchLookupsReducer } from '@gitbutler/shared/branches/latestBranchLookupSlice'; | ||
import { patchSectionsReducer } from '@gitbutler/shared/branches/patchSectionsSlice'; | ||
import { patchesReducer } from '@gitbutler/shared/branches/patchesSlice'; | ||
import { chatChannelsReducer } from '@gitbutler/shared/chat/chatChannelsSlice'; | ||
import { feedsReducer } from '@gitbutler/shared/feeds/feedsSlice'; | ||
import { postsReducer } from '@gitbutler/shared/feeds/postsSlice'; | ||
import { organizationsReducer } from '@gitbutler/shared/organizations/organizationsSlice'; | ||
import { projectsReducer } from '@gitbutler/shared/organizations/projectsSlice'; | ||
import { repositoryIdLookupsReducer } from '@gitbutler/shared/organizations/repositoryIdLookupsSlice'; | ||
import { exampleReducer } from '@gitbutler/shared/redux/example'; | ||
import { AppDispatch, AppState } from '@gitbutler/shared/redux/store.svelte'; | ||
import { usersReducer } from '@gitbutler/shared/users/usersSlice'; | ||
import { configureStore, createSelector, createSlice } from '@reduxjs/toolkit'; | ||
|
||
type DesktopOnly = { | ||
value: number; | ||
}; | ||
|
||
const desktopOnly = createSlice({ | ||
name: 'desktopOnly', | ||
initialState: { value: 69 } as DesktopOnly, | ||
reducers: { | ||
increment: (state) => { | ||
state.value += 1; | ||
}, | ||
decrement: (state) => { | ||
state.value -= 1; | ||
} | ||
} | ||
}); | ||
|
||
export const { increment: desktopIncrement, decrement: desktopDecrement } = desktopOnly.actions; | ||
|
||
export class DesktopDispatch extends AppDispatch { | ||
constructor(readonly dispatch: typeof DesktopState.prototype._store.dispatch) { | ||
super(dispatch); | ||
import { reduxApi } from './api'; | ||
import { configureStore } from '@reduxjs/toolkit'; | ||
import type { Tauri } from '$lib/backend/tauri'; | ||
|
||
export class DesktopRedux { | ||
readonly store: ReturnType<typeof createStore>; | ||
readonly dispatch: typeof DesktopRedux.prototype.store.dispatch; | ||
|
||
constructor(readonly tauri: Tauri) { | ||
this.store = createStore(tauri); | ||
this.dispatch = this.store.dispatch; | ||
this.rootState$ = this.store.getState(); | ||
|
||
$effect(() => | ||
this.store.subscribe(() => { | ||
this.rootState$ = this.store.getState(); | ||
}) | ||
); | ||
} | ||
} | ||
|
||
interface AppDesktopOnlyState { | ||
readonly desktopOnly: ReturnType<typeof desktopOnly.reducer>; | ||
rootState$ = $state({} as ReturnType<typeof this.store.getState>); | ||
} | ||
|
||
// There is some minor duplication in terms of what is declared, but we do get | ||
// type errors if you are missing a base reducer in the configureStore call. | ||
// As such, there shouldn't be any concern about the two getting out of sync. | ||
// This is due to limitations in typescript. | ||
export class DesktopState extends AppState implements AppDesktopOnlyState { | ||
/** | ||
* The base store. | ||
* | ||
* This is a low level API and should not be used directly. | ||
* @private | ||
*/ | ||
readonly _store = configureStore({ | ||
/** | ||
* We need this function in order to declare the store type in `DesktopState` | ||
* and then assign the value in the constructor. | ||
*/ | ||
function createStore(tauri: Tauri) { | ||
return configureStore({ | ||
reducer: { | ||
examples: exampleReducer, | ||
posts: postsReducer, | ||
feeds: feedsReducer, | ||
orgnaizations: organizationsReducer, | ||
users: usersReducer, | ||
projects: projectsReducer, | ||
branches: branchesReducer, | ||
patches: patchesReducer, | ||
patchSections: patchSectionsReducer, | ||
chatChannels: chatChannelsReducer, | ||
repositoryIdLookups: repositoryIdLookupsReducer, | ||
latestBranchLookups: latestBranchLookupsReducer, | ||
branchReviewListings: branchReviewListingsReducer, | ||
desktopOnly: desktopOnly.reducer | ||
api: reduxApi.reducer | ||
}, | ||
middleware: (getDefaultMiddleware) => { | ||
return getDefaultMiddleware({ | ||
thunk: { extraArgument: { tauri } } | ||
}).concat(reduxApi.middleware); | ||
} | ||
}); | ||
|
||
readonly appDispatch = new DesktopDispatch(this._store.dispatch); | ||
|
||
/** | ||
* Used to access the store directly. It is recommended to access state via | ||
* selectors as they are more efficient. | ||
*/ | ||
rootState = $state<ReturnType<typeof this._store.getState>>(this._store.getState()); | ||
|
||
protected selectSelf(state: ReturnType<typeof this._store.getState>) { | ||
return state; | ||
} | ||
|
||
private readonly selectDesktopOnly = createSelector( | ||
[this.selectSelf], | ||
(rootState) => rootState.desktopOnly | ||
); | ||
readonly desktopOnly = $derived(this.selectDesktopOnly(this.rootState)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* Return type of Tauri `stacks` command. | ||
*/ | ||
export type Stack = { | ||
id: string; | ||
branchNames: string[]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { reduxApi } from '$lib/redux/api'; | ||
import { DesktopRedux } from '$lib/redux/store.svelte'; | ||
import type { Stack } from './stack'; | ||
|
||
enum Tags { | ||
Stacks = 'Stacks' | ||
} | ||
|
||
export class StackService { | ||
private stacksApi = reduxApi.injectEndpoints({ | ||
endpoints: (build) => ({ | ||
/** Fetches all stacks. */ | ||
get: build.query<Stack[], { projectId: string }>({ | ||
query: ({ projectId }) => ({ command: 'stacks', params: { projectId } }), | ||
providesTags: [Tags.Stacks] | ||
}), | ||
new: build.mutation<Stack, { projectId: string }>({ | ||
query: ({ projectId }) => ({ | ||
command: 'create_virtual_branch', | ||
params: { projectId, branch: {} } | ||
}), | ||
invalidatesTags: [Tags.Stacks] | ||
}) | ||
}) | ||
}); | ||
|
||
constructor(private state: DesktopRedux) {} | ||
|
||
poll(projectId: string) { | ||
$effect(() => { | ||
const { unsubscribe } = this.state.dispatch( | ||
this.stacksApi.endpoints.get.initiate({ projectId }) | ||
); | ||
return () => { | ||
unsubscribe(); | ||
}; | ||
}); | ||
} | ||
|
||
select(projectId: string) { | ||
return this.stacksApi.endpoints.get.select({ projectId }); | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/promise-function-async | ||
new(projectId: string) { | ||
return this.state.dispatch(this.stacksApi.endpoints.new.initiate({ projectId })); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.