mirror of
https://github.com/tulir/gomuks.git
synced 2025-04-19 18:13:41 -05:00
web/settings: add hacky preference editor
This commit is contained in:
parent
9babbe0fc7
commit
63a1aa6cb7
3 changed files with 172 additions and 3 deletions
|
@ -6,4 +6,12 @@ div.settings-view {
|
||||||
> h2 {
|
> h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
div.preference {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,18 +13,179 @@
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
import { RoomStateStore } from "@/api/statestore"
|
import { use, useCallback } from "react"
|
||||||
import JSONView from "@/ui/util/JSONView.tsx"
|
import { RoomStateStore, usePreferences } from "@/api/statestore"
|
||||||
|
import { Preference, PreferenceContext, PreferenceValueType, Preferences, preferences } from "@/api/types/preferences"
|
||||||
|
import ClientContext from "../ClientContext.ts"
|
||||||
|
import JSONView from "../util/JSONView.tsx"
|
||||||
|
import Toggle from "../util/Toggle.tsx"
|
||||||
|
import CloseIcon from "@/icons/close.svg?react"
|
||||||
import "./SettingsView.css"
|
import "./SettingsView.css"
|
||||||
|
|
||||||
|
interface PreferenceCellProps<T extends PreferenceValueType> {
|
||||||
|
context: PreferenceContext
|
||||||
|
name: keyof Preferences
|
||||||
|
pref: Preference<T>
|
||||||
|
setPref: SetPrefFunc
|
||||||
|
value: T | undefined
|
||||||
|
inheritedValue: T
|
||||||
|
}
|
||||||
|
|
||||||
|
const useRemover = (
|
||||||
|
context: PreferenceContext, setPref: SetPrefFunc, name: keyof Preferences, value: PreferenceValueType | undefined,
|
||||||
|
) => {
|
||||||
|
const onClear = useCallback(() => {
|
||||||
|
setPref(context, name, undefined)
|
||||||
|
}, [setPref, context, name])
|
||||||
|
if (value === undefined) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <button onClick={onClear}><CloseIcon /></button>
|
||||||
|
}
|
||||||
|
|
||||||
|
const BooleanPreferenceCell = ({ context, name, setPref, value, inheritedValue }: PreferenceCellProps<boolean>) => {
|
||||||
|
const onChange = useCallback((evt: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setPref(context, name, evt.target.checked)
|
||||||
|
}, [setPref, context, name])
|
||||||
|
return <div className="preference boolean-preference">
|
||||||
|
<Toggle checked={value ?? inheritedValue} onChange={onChange}/>
|
||||||
|
{useRemover(context, setPref, name, value)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectPreferenceCell = ({ context, name, pref, setPref, value, inheritedValue }: PreferenceCellProps<string>) => {
|
||||||
|
const onChange = useCallback((evt: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
setPref(context, name, evt.target.value)
|
||||||
|
}, [setPref, context, name])
|
||||||
|
const remover = useRemover(context, setPref, name, value)
|
||||||
|
if (!pref.allowedValues) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <div className="preference select-preference">
|
||||||
|
<select value={value ?? inheritedValue} onChange={onChange}>
|
||||||
|
{pref.allowedValues.map(value =>
|
||||||
|
<option key={value} value={value}>{value}</option>)}
|
||||||
|
</select>
|
||||||
|
{remover}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetPrefFunc = (context: PreferenceContext, key: keyof Preferences, value: PreferenceValueType | undefined) => void
|
||||||
|
|
||||||
|
interface PreferenceRowProps {
|
||||||
|
name: keyof Preferences
|
||||||
|
pref: Preference
|
||||||
|
setPref: SetPrefFunc
|
||||||
|
globalServer?: PreferenceValueType
|
||||||
|
globalLocal?: PreferenceValueType
|
||||||
|
roomServer?: PreferenceValueType
|
||||||
|
roomLocal?: PreferenceValueType
|
||||||
|
}
|
||||||
|
|
||||||
|
const PreferenceRow = ({
|
||||||
|
name, pref, setPref, globalServer, globalLocal, roomServer, roomLocal,
|
||||||
|
}: PreferenceRowProps) => {
|
||||||
|
const makeContentCell = (
|
||||||
|
context: PreferenceContext,
|
||||||
|
val: PreferenceValueType | undefined,
|
||||||
|
inheritedVal: PreferenceValueType,
|
||||||
|
) => {
|
||||||
|
const prefType = typeof pref.defaultValue
|
||||||
|
if (prefType === "boolean") {
|
||||||
|
return <BooleanPreferenceCell
|
||||||
|
name={name}
|
||||||
|
setPref={setPref}
|
||||||
|
context={context}
|
||||||
|
pref={pref as Preference<boolean>}
|
||||||
|
value={val as boolean | undefined}
|
||||||
|
inheritedValue={inheritedVal as boolean}
|
||||||
|
/>
|
||||||
|
} else if (typeof prefType === "string" && pref.allowedValues) {
|
||||||
|
return <SelectPreferenceCell
|
||||||
|
name={name}
|
||||||
|
setPref={setPref}
|
||||||
|
context={context}
|
||||||
|
pref={pref as Preference<string>}
|
||||||
|
value={val as string | undefined}
|
||||||
|
inheritedValue={inheritedVal as string}
|
||||||
|
/>
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let inherit: PreferenceValueType
|
||||||
|
return <tr>
|
||||||
|
<th title={pref.description}>{pref.displayName}</th>
|
||||||
|
<td>{makeContentCell(PreferenceContext.Account, globalServer, inherit = pref.defaultValue)}</td>
|
||||||
|
<td>{makeContentCell(PreferenceContext.Device, globalLocal, inherit = globalServer ?? inherit)}</td>
|
||||||
|
<td>{makeContentCell(PreferenceContext.RoomAccount, roomServer, inherit = globalLocal ?? inherit)}</td>
|
||||||
|
<td>{makeContentCell(PreferenceContext.RoomDevice, roomLocal, inherit = roomServer ?? inherit)}</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
|
||||||
interface SettingsViewProps {
|
interface SettingsViewProps {
|
||||||
room: RoomStateStore
|
room: RoomStateStore
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingsView = ({ room }: SettingsViewProps) => {
|
const SettingsView = ({ room }: SettingsViewProps) => {
|
||||||
|
const client = use(ClientContext)!
|
||||||
|
const setPref = useCallback((context: PreferenceContext, key: keyof Preferences, value: PreferenceValueType | undefined)=> {
|
||||||
|
if (context === PreferenceContext.Account) {
|
||||||
|
client.rpc.setAccountData("fi.mau.gomuks.preferences", {
|
||||||
|
...client.store.serverPreferenceCache,
|
||||||
|
[key]: value,
|
||||||
|
})
|
||||||
|
} else if (context === PreferenceContext.Device) {
|
||||||
|
if (value === undefined) {
|
||||||
|
delete client.store.localPreferenceCache[key]
|
||||||
|
} else {
|
||||||
|
(client.store.localPreferenceCache[key] as PreferenceValueType) = value
|
||||||
|
}
|
||||||
|
} else if (context === PreferenceContext.RoomAccount) {
|
||||||
|
client.rpc.setAccountData("fi.mau.gomuks.preferences", {
|
||||||
|
...room.serverPreferenceCache,
|
||||||
|
[key]: value,
|
||||||
|
}, room.roomID)
|
||||||
|
} else if (context === PreferenceContext.RoomDevice) {
|
||||||
|
if (value === undefined) {
|
||||||
|
delete room.localPreferenceCache[key]
|
||||||
|
} else {
|
||||||
|
(room.localPreferenceCache[key] as PreferenceValueType) = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [client, room])
|
||||||
|
usePreferences(client.store, room)
|
||||||
|
const globalServer = client.store.serverPreferenceCache
|
||||||
|
const globalLocal = client.store.localPreferenceCache
|
||||||
|
const roomServer = room.serverPreferenceCache
|
||||||
|
const roomLocal = room.localPreferenceCache
|
||||||
return <>
|
return <>
|
||||||
<h2>Settings</h2>
|
<h2>Settings</h2>
|
||||||
<code>{room.roomID}</code>
|
<code>{room.roomID}</code>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>name</th>
|
||||||
|
<th>Account</th>
|
||||||
|
<th>Device</th>
|
||||||
|
<th>Room (account)</th>
|
||||||
|
<th>Room (device)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{Object.entries(preferences).map(([key, pref]) =>
|
||||||
|
<PreferenceRow
|
||||||
|
key={key}
|
||||||
|
name={key as keyof Preferences}
|
||||||
|
pref={pref}
|
||||||
|
setPref={setPref}
|
||||||
|
globalServer={globalServer[key as keyof Preferences]}
|
||||||
|
globalLocal={globalLocal[key as keyof Preferences]}
|
||||||
|
roomServer={roomServer[key as keyof Preferences]}
|
||||||
|
roomLocal={roomLocal[key as keyof Preferences]}
|
||||||
|
/>)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
<JSONView data={room.preferences} />
|
<JSONView data={room.preferences} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ input.toggle {
|
||||||
border: 1px solid var(--disabled-color);
|
border: 1px solid var(--disabled-color);
|
||||||
border-radius: 1.5em;
|
border-radius: 1.5em;
|
||||||
width: 3.5em;
|
width: 3.5em;
|
||||||
height: 2em;
|
/*height: 2em;*/
|
||||||
padding: calc(.25em - 1px);
|
padding: calc(.25em - 1px);
|
||||||
transition: background-color var(--transition-duration), border-color var(--transition-duration);
|
transition: background-color var(--transition-duration), border-color var(--transition-duration);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue