move settings developer tool to new sdk

This commit is contained in:
Ajay Bura 2026-07-24 21:48:35 +05:30
commit c4f58415db
4 changed files with 73 additions and 68 deletions

View file

@ -14,6 +14,7 @@ import {
Scroll,
config,
} from 'folds';
import { AccountDataEvent } from 'neurone/lib/api/types';
import { Cursor } from '../plugins/text-area';
import { syntaxErrorPosition } from '../utils/dom';
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
@ -27,17 +28,12 @@ const EDITOR_INTENT_SPACE_COUNT = 2;
export type AccountDataSubmitCallback = (type: string, content: object) => Promise<void>;
type AccountDataInfo = {
type: string;
content: object;
};
type AccountDataEditProps = {
type: string;
defaultContent: string;
submitChange: AccountDataSubmitCallback;
onCancel: () => void;
onSave: (info: AccountDataInfo) => void;
onSave: (info: AccountDataEvent) => void;
};
function AccountDataEdit({
type,
@ -243,34 +239,30 @@ function AccountDataView({ type, defaultContent, onEdit }: AccountDataViewProps)
}
export type AccountDataEditorProps = {
type?: string;
content?: object;
event?: AccountDataEvent;
submitChange: AccountDataSubmitCallback;
requestClose: () => void;
};
export function AccountDataEditor({
type,
content,
submitChange,
requestClose,
}: AccountDataEditorProps) {
const [data, setData] = useState<AccountDataInfo>({
type: type ?? '',
content: content ?? {},
});
export function AccountDataEditor({ event, submitChange, requestClose }: AccountDataEditorProps) {
const [data, setData] = useState<AccountDataEvent>(
event ?? {
type: '',
content: {},
}
);
const [edit, setEdit] = useState(!type);
const [edit, setEdit] = useState(!data.type);
const closeEdit = useCallback(() => {
if (!type) {
if (!event) {
requestClose();
return;
}
setEdit(false);
}, [type, requestClose]);
}, [event, requestClose]);
const handleSave = useCallback((info: AccountDataInfo) => {
const handleSave = useCallback((info: AccountDataEvent) => {
setData(info);
setEdit(false);
}, []);

View file

@ -1,29 +1,20 @@
import React, { useCallback, useState } from 'react';
import React from 'react';
import { Box, Text, Icon, Icons, Button, MenuItem } from 'folds';
import { AccountDataEvent } from 'neurone/lib/api/types';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
import { SettingTile } from '../../../components/setting-tile';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useAccountDataCallback } from '../../../hooks/useAccountDataCallback';
import { CutoutCard } from '../../../components/cutout-card';
import { useAccountDataEvents } from '../../../hooks/storage/useAccountData';
type AccountDataProps = {
expand: boolean;
onExpandToggle: (expand: boolean) => void;
onSelect: (type: string | null) => void;
onSelect: (type: AccountDataEvent | null) => void;
};
export function AccountData({ expand, onExpandToggle, onSelect }: AccountDataProps) {
const mx = useMatrixClient();
const [accountDataTypes, setAccountDataKeys] = useState(() =>
Array.from(mx.store.accountData.keys())
);
useAccountDataCallback(
mx,
useCallback(() => {
setAccountDataKeys(Array.from(mx.store.accountData.keys()));
}, [mx])
);
const accountDataEventsResult = useAccountDataEvents();
const accountDataEvents = accountDataEventsResult.value;
return (
<Box direction="Column" gap="100">
@ -57,7 +48,7 @@ export function AccountData({ expand, onExpandToggle, onSelect }: AccountDataPro
<Box direction="Column" gap="100">
<Box justifyContent="SpaceBetween">
<Text size="L400">Events</Text>
<Text size="L400">Total: {accountDataTypes.length}</Text>
{accountDataEvents && <Text size="L400">Total: {accountDataEvents.length}</Text>}
</Box>
<CutoutCard>
<MenuItem
@ -74,23 +65,25 @@ export function AccountData({ expand, onExpandToggle, onSelect }: AccountDataPro
</Text>
</Box>
</MenuItem>
{accountDataTypes.sort().map((type) => (
<MenuItem
key={type}
variant="Surface"
fill="None"
size="300"
radii="0"
after={<Icon size="50" src={Icons.ChevronRight} />}
onClick={() => onSelect(type)}
>
<Box grow="Yes">
<Text size="T200" truncate>
{type}
</Text>
</Box>
</MenuItem>
))}
{accountDataEvents
?.sort((e1, e2) => (e1 < e2 ? -1 : 1))
.map((event) => (
<MenuItem
key={event.type}
variant="Surface"
fill="None"
size="300"
radii="0"
after={<Icon size="50" src={Icons.ChevronRight} />}
onClick={() => onSelect(event)}
>
<Box grow="Yes">
<Text size="T200" truncate>
{event.type}
</Text>
</Box>
</MenuItem>
))}
</CutoutCard>
</Box>
)}

View file

@ -1,42 +1,52 @@
import React, { useCallback, useState } from 'react';
import { Box, Text, IconButton, Icon, Icons, Scroll, Switch, Button } from 'folds';
import { putAccountData } from 'neurone/lib/api/matrix/client/v3/user';
import { parseMatrixResp } from 'neurone/lib/matrix-request';
import { AccountDataEvent } from 'neurone/lib/api/types';
import { Page, PageContent, PageHeader } from '../../../components/page';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
import { SettingTile } from '../../../components/setting-tile';
import { useSetting } from '../../../state/hooks/settings';
import { settingsAtom } from '../../../state/settings';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import {
AccountDataEditor,
AccountDataSubmitCallback,
} from '../../../components/AccountDataEditor';
import { copyToClipboard } from '../../../utils/dom';
import { useClient } from '../../../hooks/useClient';
import { AccountData } from './AccountData';
type DeveloperToolsProps = {
requestClose: () => void;
};
export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
const mx = useMatrixClient();
const ct = useClient();
const [developerTools, setDeveloperTools] = useSetting(settingsAtom, 'developerTools');
const [expand, setExpend] = useState(false);
const [accountDataType, setAccountDataType] = useState<string | null>();
const [editAccountData, setEditAccountData] = useState<AccountDataEvent | null>();
const submitAccountData: AccountDataSubmitCallback = useCallback(
async (type, content) => {
await mx.setAccountData(type, content);
const resp = await ct.requestAuthJSON(
putAccountData({
pathParams: { type, userId: ct.session.userId },
body: content,
})
);
const [err] = await parseMatrixResp(resp);
if (err) throw new Error(err.data.error ?? err.data.errcode);
},
[mx]
[ct]
);
if (accountDataType !== undefined) {
if (editAccountData !== undefined) {
return (
<AccountDataEditor
type={accountDataType ?? undefined}
content={accountDataType ? mx.getAccountData(accountDataType)?.getContent() : undefined}
event={editAccountData ?? undefined}
submitChange={submitAccountData}
requestClose={() => setAccountDataType(undefined)}
requestClose={() => setEditAccountData(undefined)}
/>
);
}
@ -92,9 +102,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
description="Copy access token to clipboard."
after={
<Button
onClick={() =>
copyToClipboard(mx.getAccessToken() ?? '<NO_ACCESS_TOKEN_FOUND>')
}
onClick={() => copyToClipboard(ct.session.accessToken)}
variant="Secondary"
fill="Soft"
size="300"
@ -112,7 +120,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
<AccountData
expand={expand}
onExpandToggle={setExpend}
onSelect={setAccountDataType}
onSelect={setEditAccountData}
/>
)}
</Box>

View file

@ -23,3 +23,15 @@ export function useAccountData<T extends AccountDataEvent>(
useCallback((v) => v?.event as T | undefined, [])
);
}
export function useAccountDataEvents(): PendingObservableResult<AccountDataEvent[]> {
const ct = useClient();
const observablePromise = useMemo(() => ct.storage.accountData.observableRead.getAll(), [ct]);
const result = useObservableValuePromise(observablePromise);
return useComputedPendingObservableResult(
result,
useCallback((objs) => objs.map((o) => o.event), [])
);
}