Skip to content

Commit 1f65936

Browse files
committed
feat: Expose useConfirmDialog to ext
feat: Modify data sources in manager settings
1 parent 118a076 commit 1f65936

File tree

9 files changed

+170
-39
lines changed

9 files changed

+170
-39
lines changed

extensions/core-manager/src/components/SettingsSubsection.tsx

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { GameMetadataSource } from 'flashpoint-launcher';
2-
import { InputElement } from 'flashpoint-launcher-renderer';
1+
import { GameDataSource, GameMetadataSource } from 'flashpoint-launcher';
2+
import { ConfirmDialogProps, InputElement } from 'flashpoint-launcher-renderer';
33
import { updatePreferences } from 'flashpoint-launcher-renderer-ext/actions/preferences';
4-
import { ConfigBox, ConfigBoxInput, ConfigSection, InputField } from 'flashpoint-launcher-renderer-ext/components';
5-
import { useAppDispatch, useAppSelector } from 'flashpoint-launcher-renderer-ext/hooks';
4+
import { ConfigBox, ConfigBoxInput, ConfigSection, InputField, SimpleButton } from 'flashpoint-launcher-renderer-ext/components';
5+
import { useAppDispatch, useAppSelector, useConfirmDialog } from 'flashpoint-launcher-renderer-ext/hooks';
66
import { selectRepoUrls, setRepoUrlsAction } from '../select';
77

88

99
export function SubsectionSettings() {
1010
const dispatch = useAppDispatch();
11+
const { confirmDialog, openConfirmDialog } = useConfirmDialog();
1112
const repoUrls = useAppSelector(selectRepoUrls);
13+
const dataSources = useAppSelector(state => state.preferences.gameDataSources);
1214
const metadataSources = useAppSelector(state => state.preferences.gameMetadataSources);
1315
const metadataSourceBoxes = metadataSources.map(source => {
1416
return <MetadataRow source={source} updateSource={(source) => {
@@ -22,6 +24,25 @@ export function SubsectionSettings() {
2224
}
2325
}} />;
2426
});
27+
const dataSourceBoxes = dataSources.map((data, idx) => {
28+
return <DataRow
29+
data={data}
30+
updateData={(data) => {
31+
const newDataSources = [...dataSources];
32+
newDataSources[idx] = data;
33+
dispatch(updatePreferences({
34+
gameDataSources: newDataSources
35+
}));
36+
}}
37+
removeData={() => {
38+
const newDataSources = [...dataSources];
39+
newDataSources.splice(idx, 1);
40+
dispatch(updatePreferences({
41+
gameDataSources: newDataSources
42+
}));
43+
}}
44+
openConfirmDialog={openConfirmDialog} />;
45+
});
2546

2647
return <div className='manager-page-subsection'>
2748
<div className='manager-page-subsection-header'>Settings</div>
@@ -46,14 +67,118 @@ export function SubsectionSettings() {
4667
</div>
4768
</ConfigBox>
4869
</ConfigSection>
70+
<ConfigSection>
71+
<ConfigBox
72+
title='Data Sources'
73+
description='List of all Flashpoint data sources to pull from'
74+
swapChildren={true}>
75+
<div>
76+
<div className='manager-source-table-list'>
77+
{dataSourceBoxes}
78+
</div>
79+
<SimpleButton
80+
value={'New Data Source'}
81+
onClick={() => {
82+
const newDataSources = [...dataSources];
83+
newDataSources.push({
84+
type: '',
85+
name: '',
86+
arguments: '',
87+
});
88+
dispatch(updatePreferences({ gameDataSources: newDataSources }));
89+
}}/>
90+
</div>
91+
</ConfigBox>
92+
</ConfigSection>
93+
{confirmDialog}
4994
</div>;
5095
}
5196

97+
type DataRowProps = {
98+
data: GameDataSource;
99+
updateData: (newData: GameDataSource) => void;
100+
removeData: () => void;
101+
openConfirmDialog: (props: Omit<ConfirmDialogProps, 'onResult'>) => Promise<number>;
102+
}
103+
52104
type MetadataRowProps = {
53105
source: GameMetadataSource;
54106
updateSource: (newSource: GameMetadataSource) => void;
55107
}
56108

109+
function DataRow({ data, updateData, removeData, openConfirmDialog }: DataRowProps) {
110+
const onUpdateType = (event: React.ChangeEvent<InputElement>) => {
111+
updateData({
112+
...data,
113+
type: event.target.value
114+
});
115+
};
116+
const onUpdateName = (event: React.ChangeEvent<InputElement>) => {
117+
updateData({
118+
...data,
119+
name: event.target.value
120+
});
121+
};
122+
const onUpdateArguments = (event: React.ChangeEvent<InputElement>) => {
123+
updateData({
124+
...data,
125+
arguments: event.target.value
126+
});
127+
};
128+
129+
return (
130+
<>
131+
<table className='curate-box-table'>
132+
<tbody>
133+
<tr className='curate-box-row'>
134+
<th className='curate-box-row__title'>Type</th>
135+
<td className='curate-box-row__content'>
136+
<InputField
137+
text={data.type || ''}
138+
placeholder={'No Type'}
139+
onChange={onUpdateType}
140+
editable={true} />
141+
</td>
142+
</tr>
143+
<tr className='curate-box-row'>
144+
<th className='curate-box-row__title'>Name</th>
145+
<td className='curate-box-row__content'>
146+
<InputField
147+
text={data.name || ''}
148+
placeholder={'No Name'}
149+
onChange={onUpdateName}
150+
editable={true} />
151+
</td>
152+
</tr>
153+
<tr className='curate-box-row'>
154+
<th className='curate-box-row__title'>Arguments</th>
155+
<td className='curate-box-row__content'>
156+
<InputField
157+
text={data.arguments}
158+
placeholder={'No Arguments'}
159+
onChange={onUpdateArguments}
160+
editable={true} />
161+
</td>
162+
</tr>
163+
</tbody>
164+
</table>
165+
<SimpleButton
166+
className='manager-data-delete-button'
167+
value='Delete'
168+
onClick={async () => {
169+
const res = await openConfirmDialog({
170+
message: 'Deleting data source, are you sure?',
171+
buttons: ['Yes', 'No'],
172+
cancelId: 1
173+
});
174+
if (res === 0) {
175+
removeData();
176+
}
177+
}} />
178+
</>
179+
);
180+
}
181+
57182
function MetadataRow({ source, updateSource }: MetadataRowProps) {
58183
const onUpdateName = (event: React.ChangeEvent<InputElement>) => {
59184
updateSource({
@@ -113,5 +238,5 @@ function MetadataRow({ source, updateSource }: MetadataRowProps) {
113238
</tr>
114239
</tbody>
115240
</table>
116-
)
241+
);
117242
}

extensions/core-manager/static/core-manager.css

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,10 @@
9393
margin-left: 0.3rem;
9494
}
9595

96-
.manager-source-table {
97-
text-align: left;
96+
.manager-source-table-list > table:not(:first-child) {
97+
border-top: 1px solid var(--layout__home-page-box-border);
9898
}
9999

100-
.manager-source-table-row-key {
101-
font-weight: 600;
102-
padding-right: 0.3rem;
103-
}
104-
105-
.manager-source-table-list > :not(:last-child) {
106-
border-bottom: 1px solid var(--layout__home-page-box-border);
100+
.manager-data-delete-button {
101+
margin-bottom: 0.2rem;
107102
}

src/back/GameDataProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { DownloadDetails } from '@shared/back/types';
22
import { downloadFile } from '@shared/Util';
33
import { getGameDataFilename } from '@shared/utils/misc';
44
import { GameData, GameDataProvider, GameDataSource } from 'flashpoint-launcher';
5-
import * as fs from 'node:fs';
65
import * as crypto from 'node:crypto';
6+
import * as fs from 'node:fs';
77
import * as path from 'node:path';
88
import { axios } from './dns';
99
import { importGameDataSkipHash } from './download';
@@ -17,7 +17,7 @@ export const GameDataProviderRaw: GameDataProvider = {
1717
}
1818

1919
const filename = getGameDataFilename(gameData);
20-
const fullUrl = new URL(filename, source.arguments[0]).href;
20+
const fullUrl = new URL(filename, source.arguments).href;
2121
console.log(fullUrl);
2222
const tempPath = path.join(dataPacksFolderPath, `${filename}.temp`);
2323
await downloadFile(axios, fullUrl, tempPath, abortSignal, onProgress, onDetails);

src/renderer/components/ConfirmDialog.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
1+
import { ConfirmDialogProps } from 'flashpoint-launcher-renderer';
12
import { SimpleButton } from './SimpleButton';
23

3-
export type ConfirmDialogProps = {
4-
message: string;
5-
buttons: string[];
6-
// eslint-disable-next-line react/no-unused-prop-types
7-
cancelId?: number;
8-
onResult: (result: number) => void;
9-
}
10-
114
export function ConfirmDialog(props: ConfirmDialogProps) {
125
return (
136
<div className='confirm-dialog'>

src/renderer/components/app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { resolveNewDialog } from '@renderer/dialog';
44
import { getFpfssConsentExt, saveFpfssConsentExt } from '@renderer/fpfss';
55
import { useView } from '@renderer/hooks/search';
66
import { useAppDispatch, useAppSelector } from '@renderer/hooks/useAppSelector';
7+
import { useConfirmDialog } from '@renderer/hooks/useConfirmDialog';
78
import { useContextMenu } from '@renderer/hooks/useContextMenu';
89
import { useLocalization } from '@renderer/hooks/useLocalization';
910
import { createGroup, modifyCurations, replaceCurations, setContentTree, setCurateLoaded, setCurationTemplates, setLock, setSelectedCurations } from '@renderer/store/curate/slice';
@@ -482,6 +483,7 @@ function addExtIntercepts() {
482483
useAppSelector,
483484
useContextMenu,
484485
useLocalization,
486+
useConfirmDialog,
485487
} satisfies typeof import('flashpoint-launcher-renderer-ext/hooks');
486488

487489
(window as any)['flashpoint-launcher-renderer-ext/actions/main'] = {

src/renderer/containers/withConfirmDialog.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { ConfirmDialog, ConfirmDialogProps } from '@renderer/components/ConfirmDialog';
1+
import { ConfirmDialog } from '@renderer/components/ConfirmDialog';
22
import { FloatingContainer } from '@renderer/components/FloatingContainer';
33
import { Subtract } from '@shared/interfaces';
4+
import { ConfirmDialogProps } from 'flashpoint-launcher-renderer';
45
import * as React from 'react';
56

67
type ConfirmDialogExtraProps = ConfirmDialogProps & {

src/renderer/hooks/useConfirmDialog.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import { ConfirmDialog, ConfirmDialogProps } from '@renderer/components/ConfirmDialog';
1+
import { ConfirmDialog } from '@renderer/components/ConfirmDialog';
22
import { FloatingContainer } from '@renderer/components/FloatingContainer';
3-
import { Activity, ReactNode, useState } from 'react';
4-
5-
type ConfirmDialogState = {
6-
confirmDialog: ReactNode;
7-
openConfirmDialog: (props: Omit<ConfirmDialogProps, 'onResult'>) => Promise<number>
8-
}
3+
import { ConfirmDialogProps, ConfirmDialogState } from 'flashpoint-launcher-renderer';
4+
import { Activity, useState } from 'react';
95

106
export function useConfirmDialog(): ConfirmDialogState {
117
const [isOpen, setIsOpen] = useState(false);

src/shared/preferences/util.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,17 +358,24 @@ function parseAppPathOverride(parser: IObjectParserProp<any>): AppPathOverride {
358358
return override;
359359
}
360360

361+
function strOrArray(v: any) {
362+
if (Array.isArray(v)) {
363+
return v.join(' ');
364+
} else {
365+
return `${v}`;
366+
}
367+
}
368+
361369
function parseGameDataSource(parser: IObjectParserProp<GameDataSource>): GameDataSource {
362370
const source: GameDataSource = {
363371
type: 'raw',
364372
name: '',
365-
arguments: [],
366-
data: undefined
373+
arguments: ''
367374
};
375+
368376
parser.prop('type', v => source.type = str(v));
369377
parser.prop('name', v => source.name = str(v));
370-
parser.prop('arguments').arrayRaw((item, index) => source.arguments.push(item));
371-
parser.prop('data', v => source.data = v, true);
378+
parser.prop('arguments', v => source.arguments = strOrArray(v), true);
372379
return source;
373380
}
374381

typings/flashpoint-launcher.d.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,8 +1284,7 @@ declare module 'flashpoint-launcher' {
12841284
type GameDataSource = {
12851285
type: string;
12861286
name: string;
1287-
arguments: string[];
1288-
data: any;
1287+
arguments: string;
12891288
}
12901289

12911290
type GameMetadataSource = {
@@ -3563,6 +3562,18 @@ declare module 'flashpoint-launcher-renderer' {
35633562
value: any;
35643563
}
35653564

3565+
type ConfirmDialogProps = {
3566+
message: string;
3567+
buttons: string[];
3568+
cancelId?: number;
3569+
onResult: (result: number) => void;
3570+
}
3571+
3572+
type ConfirmDialogState = {
3573+
confirmDialog: ReactNode;
3574+
openConfirmDialog: (props: Omit<ConfirmDialogProps, 'onResult'>) => Promise<number>
3575+
}
3576+
35663577
declare global {
35673578
interface Window {
35683579
log: LogFuncs;
@@ -3660,7 +3671,7 @@ declare module 'flashpoint-launcher-renderer-ext/components' {
36603671
declare module 'flashpoint-launcher-renderer-ext/hooks' {
36613672
import { ThunkDispatch } from '@reduxjs/toolkit';
36623673
import { LangContainer } from 'flashpoint-launcher';
3663-
import { MenuContextStateProps, RootState } from 'flashpoint-launcher-renderer';
3674+
import { ConfirmDialogState, MenuContextStateProps, RootState } from 'flashpoint-launcher-renderer';
36643675
import { TypedUseSelectorHook } from 'react-redux';
36653676
import { Location, NavigateFunction } from 'react-router-dom';
36663677

@@ -3670,6 +3681,7 @@ declare module 'flashpoint-launcher-renderer-ext/hooks' {
36703681
const useAppSelector: TypedUseSelectorHook<RootState>;
36713682
const useContextMenu: () => MenuContextStateProps;
36723683
const useLocalization: () => LangContainer;
3684+
const useConfirmDialog: () => ConfirmDialogState;
36733685
}
36743686

36753687

0 commit comments

Comments
 (0)