this repo has no description

moonbase: Use unique IDs for extension management

Changed files
+139 -116
packages
core-extensions
src
moonbase
webpackModules
+1
packages/core-extensions/src/moonbase/types.ts
···
export type MoonbaseExtension = {
id: string;
manifest: ExtensionManifest | RepositoryManifest;
source: DetectedExtension["source"];
state: ExtensionState;
···
export type MoonbaseExtension = {
id: string;
+
uniqueId: number;
manifest: ExtensionManifest | RepositoryManifest;
source: DetectedExtension["source"];
state: ExtensionState;
+92 -80
packages/core-extensions/src/moonbase/webpackModules/stores.ts
···
import { Config, ExtensionLoadSource } from "@moonlight-mod/types";
-
import {
-
ExtensionState,
-
MoonbaseExtension,
-
MoonbaseNatives,
-
RepositoryManifest
-
} from "../types";
import Flux from "@moonlight-mod/wp/common_flux";
import Dispatcher from "@moonlight-mod/wp/common_fluxDispatcher";
···
class MoonbaseSettingsStore extends Flux.Store<any> {
private origConfig: Config;
private config: Config;
modified: boolean;
submitting: boolean;
installing: boolean;
-
extensions: { [id: string]: MoonbaseExtension };
-
updates: { [id: string]: { version: string; download: string } };
constructor() {
super(Dispatcher);
this.origConfig = moonlightNode.config;
this.config = this.clone(this.origConfig);
this.modified = false;
this.submitting = false;
···
this.extensions = {};
this.updates = {};
for (const ext of moonlightNode.extensions) {
-
const existingExtension = this.extensions[ext.id];
-
if (existingExtension != null) continue;
-
-
this.extensions[ext.id] = {
...ext,
state: moonlight.enabledExtensions.has(ext.id)
? ExtensionState.Enabled
: ExtensionState.Disabled
···
for (const [repo, exts] of Object.entries(ret)) {
try {
for (const ext of exts) {
-
try {
-
const existingExtension = this.extensions[ext.id];
-
if (existingExtension !== undefined) {
-
if (this.hasUpdate(repo, ext, existingExtension)) {
-
this.updates[ext.id] = {
-
version: ext.version!,
-
download: ext.download
-
};
-
}
-
this.extensions[ext.id].manifest = ext;
-
this.extensions[ext.id].source = {
-
type: ExtensionLoadSource.Normal,
-
url: repo
};
-
-
continue;
}
-
this.extensions[ext.id] = {
-
id: ext.id,
-
manifest: ext,
-
source: { type: ExtensionLoadSource.Normal, url: repo },
-
state: ExtensionState.NotDownloaded
-
};
-
} catch (e) {
-
logger.error(`Error processing extension ${ext.id}`, e);
}
}
} catch (e) {
logger.error(`Error processing repository ${repo}`, e);
···
});
}
-
// this logic sucks so bad lol
-
private hasUpdate(
-
repo: string,
-
repoExt: RepositoryManifest,
-
existing: MoonbaseExtension
-
) {
return (
-
existing.source.type === ExtensionLoadSource.Normal &&
-
existing.source.url != null &&
-
existing.source.url === repo &&
-
repoExt.version != null &&
-
existing.manifest.version !== repoExt.version
);
}
···
return this.modified;
}
-
getExtension(id: string) {
-
return this.extensions[id];
}
-
getExtensionName(id: string) {
-
return Object.prototype.hasOwnProperty.call(this.extensions, id)
-
? this.extensions[id].manifest.meta?.name ?? id
-
: id;
}
-
getExtensionUpdate(id: string) {
-
return Object.prototype.hasOwnProperty.call(this.updates, id)
-
? this.updates[id]
-
: null;
}
-
getExtensionEnabled(id: string) {
-
const val = this.config.extensions[id];
if (val == null) return false;
return typeof val === "boolean" ? val : val.enabled;
}
-
getExtensionConfig<T>(id: string, key: string): T | undefined {
-
const defaultValue = this.extensions[id].manifest.settings?.[key]?.default;
const clonedDefaultValue = this.clone(defaultValue);
-
const cfg = this.config.extensions[id];
if (cfg == null || typeof cfg === "boolean") return clonedDefaultValue;
return cfg.config?.[key] ?? clonedDefaultValue;
}
-
getExtensionConfigName(id: string, key: string) {
-
return this.extensions[id].manifest.settings?.[key]?.displayName ?? key;
}
-
getExtensionConfigDescription(id: string, key: string) {
-
return this.extensions[id].manifest.settings?.[key]?.description;
}
-
setExtensionConfig(id: string, key: string, value: any) {
-
const oldConfig = this.config.extensions[id];
const newConfig =
typeof oldConfig === "boolean"
? {
···
config: { ...(oldConfig?.config ?? {}), [key]: value }
};
-
this.config.extensions[id] = newConfig;
this.modified = this.isModified();
this.emitChange();
}
-
setExtensionEnabled(id: string, enabled: boolean) {
-
let val = this.config.extensions[id];
if (val == null) {
-
this.config.extensions[id] = { enabled };
this.modified = this.isModified();
this.emitChange();
return;
···
val.enabled = enabled;
}
-
this.config.extensions[id] = val;
this.modified = this.isModified();
this.emitChange();
}
-
async installExtension(id: string) {
-
const ext = this.getExtension(id);
if (!("download" in ext.manifest)) {
throw new Error("Extension has no download URL");
}
this.installing = true;
try {
-
const url = this.updates[id]?.download ?? ext.manifest.download;
await natives.installExtension(ext.manifest, url, ext.source.url!);
if (ext.state === ExtensionState.NotDownloaded) {
-
this.extensions[id].state = ExtensionState.Disabled;
}
-
delete this.updates[id];
} catch (e) {
logger.error("Error installing extension:", e);
}
···
this.emitChange();
}
-
async deleteExtension(id: string) {
-
const ext = this.getExtension(id);
if (ext == null) return;
this.installing = true;
try {
await natives.deleteExtension(ext.id);
-
this.extensions[id].state = ExtensionState.NotDownloaded;
} catch (e) {
logger.error("Error deleting extension:", e);
}
···
import { Config, ExtensionLoadSource } from "@moonlight-mod/types";
+
import { ExtensionState, MoonbaseExtension, MoonbaseNatives } from "../types";
import Flux from "@moonlight-mod/wp/common_flux";
import Dispatcher from "@moonlight-mod/wp/common_fluxDispatcher";
···
class MoonbaseSettingsStore extends Flux.Store<any> {
private origConfig: Config;
private config: Config;
+
private extensionIndex: number;
modified: boolean;
submitting: boolean;
installing: boolean;
+
extensions: { [id: number]: MoonbaseExtension };
+
updates: { [id: number]: { version: string; download: string } };
constructor() {
super(Dispatcher);
this.origConfig = moonlightNode.config;
this.config = this.clone(this.origConfig);
+
this.extensionIndex = 0;
this.modified = false;
this.submitting = false;
···
this.extensions = {};
this.updates = {};
for (const ext of moonlightNode.extensions) {
+
const uniqueId = this.extensionIndex++;
+
this.extensions[uniqueId] = {
...ext,
+
uniqueId,
state: moonlight.enabledExtensions.has(ext.id)
? ExtensionState.Enabled
: ExtensionState.Disabled
···
for (const [repo, exts] of Object.entries(ret)) {
try {
for (const ext of exts) {
+
const uniqueId = this.extensionIndex++;
+
const extensionData = {
+
id: ext.id,
+
uniqueId,
+
manifest: ext,
+
source: { type: ExtensionLoadSource.Normal, url: repo },
+
state: ExtensionState.NotDownloaded
+
};
+
if (this.alreadyExists(extensionData)) {
+
if (this.hasUpdate(extensionData)) {
+
this.updates[uniqueId] = {
+
version: ext.version!,
+
download: ext.download
};
}
+
continue;
}
+
+
this.extensions[uniqueId] = extensionData;
}
} catch (e) {
logger.error(`Error processing repository ${repo}`, e);
···
});
}
+
private alreadyExists(ext: MoonbaseExtension) {
+
return Object.values(this.extensions).some(
+
(e) => e.id === ext.id && e.source.url === ext.source.url
+
);
+
}
+
+
private hasUpdate(ext: MoonbaseExtension) {
+
const existing = Object.values(this.extensions).find(
+
(e) => e.id === ext.id && e.source.url === ext.source.url
+
);
+
if (existing == null) return false;
+
return (
+
existing.manifest.version !== ext.manifest.version &&
+
existing.state !== ExtensionState.NotDownloaded
);
}
···
return this.modified;
}
+
getExtension(uniqueId: number) {
+
return this.extensions[uniqueId];
}
+
getExtensionUniqueId(id: string) {
+
return Object.values(this.extensions).find((ext) => ext.id === id)
+
?.uniqueId;
+
}
+
+
getExtensionConflicting(uniqueId: number) {
+
const ext = this.getExtension(uniqueId);
+
if (ext.state !== ExtensionState.NotDownloaded) return false;
+
return Object.values(this.extensions).some(
+
(e) =>
+
e.id === ext.id &&
+
e.uniqueId !== uniqueId &&
+
e.state !== ExtensionState.NotDownloaded
+
);
+
}
+
+
getExtensionName(uniqueId: number) {
+
const ext = this.getExtension(uniqueId);
+
return ext.manifest.meta?.name ?? ext.id;
}
+
getExtensionUpdate(uniqueId: number) {
+
return this.updates[uniqueId]?.version;
}
+
getExtensionEnabled(uniqueId: number) {
+
const ext = this.getExtension(uniqueId);
+
if (ext.state === ExtensionState.NotDownloaded) return false;
+
const val = this.config.extensions[ext.id];
if (val == null) return false;
return typeof val === "boolean" ? val : val.enabled;
}
+
getExtensionConfig<T>(uniqueId: number, key: string): T | undefined {
+
const ext = this.getExtension(uniqueId);
+
const defaultValue = ext.manifest.settings?.[key]?.default;
const clonedDefaultValue = this.clone(defaultValue);
+
const cfg = this.config.extensions[ext.id];
if (cfg == null || typeof cfg === "boolean") return clonedDefaultValue;
return cfg.config?.[key] ?? clonedDefaultValue;
}
+
getExtensionConfigName(uniqueId: number, key: string) {
+
const ext = this.getExtension(uniqueId);
+
return ext.manifest.settings?.[key]?.displayName ?? key;
}
+
getExtensionConfigDescription(uniqueId: number, key: string) {
+
const ext = this.getExtension(uniqueId);
+
return ext.manifest.settings?.[key]?.description;
}
+
setExtensionConfig(uniqueId: number, key: string, value: any) {
+
const ext = this.getExtension(uniqueId);
+
const oldConfig = this.config.extensions[ext.id];
const newConfig =
typeof oldConfig === "boolean"
? {
···
config: { ...(oldConfig?.config ?? {}), [key]: value }
};
+
this.config.extensions[ext.id] = newConfig;
this.modified = this.isModified();
this.emitChange();
}
+
setExtensionEnabled(uniqueId: number, enabled: boolean) {
+
const ext = this.getExtension(uniqueId);
+
let val = this.config.extensions[ext.id];
if (val == null) {
+
this.config.extensions[ext.id] = { enabled };
this.modified = this.isModified();
this.emitChange();
return;
···
val.enabled = enabled;
}
+
this.config.extensions[ext.id] = val;
this.modified = this.isModified();
this.emitChange();
}
+
async installExtension(uniqueId: number) {
+
const ext = this.getExtension(uniqueId);
if (!("download" in ext.manifest)) {
throw new Error("Extension has no download URL");
}
this.installing = true;
try {
+
const url = this.updates[uniqueId]?.download ?? ext.manifest.download;
await natives.installExtension(ext.manifest, url, ext.source.url!);
if (ext.state === ExtensionState.NotDownloaded) {
+
this.extensions[uniqueId].state = ExtensionState.Disabled;
}
+
delete this.updates[uniqueId];
} catch (e) {
logger.error("Error installing extension:", e);
}
···
this.emitChange();
}
+
async deleteExtension(uniqueId: number) {
+
const ext = this.getExtension(uniqueId);
if (ext == null) return;
this.installing = true;
try {
await natives.deleteExtension(ext.id);
+
this.extensions[uniqueId].state = ExtensionState.NotDownloaded;
} catch (e) {
logger.error("Error deleting extension:", e);
}
+11 -9
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/card.tsx
···
const PanelButton =
spacepack.findByCode("Masks.PANEL_BUTTON")[0].exports.default;
-
export default function ExtensionCard({ id }: { id: string }) {
const [tab, setTab] = React.useState(ExtensionPage.Info);
const [restartNeeded, setRestartNeeded] = React.useState(false);
-
const { ext, enabled, busy, update } = Flux.useStateFromStores(
[MoonbaseSettingsStore],
() => {
return {
-
ext: MoonbaseSettingsStore.getExtension(id),
-
enabled: MoonbaseSettingsStore.getExtensionEnabled(id),
busy: MoonbaseSettingsStore.busy,
-
update: MoonbaseSettingsStore.getExtensionUpdate(id)
};
}
);
···
<Button
color={Button.Colors.BRAND}
submitting={busy}
onClick={() => {
-
MoonbaseSettingsStore.installExtension(id);
}}
>
Install
···
icon={TrashIcon}
tooltipText="Delete"
onClick={() => {
-
MoonbaseSettingsStore.deleteExtension(id);
}}
/>
)}
···
icon={DownloadIcon}
tooltipText="Update"
onClick={() => {
-
MoonbaseSettingsStore.installExtension(id);
}}
/>
)}
···
checked={enabled}
onChange={() => {
setRestartNeeded(true);
-
MoonbaseSettingsStore.setExtensionEnabled(id, !enabled);
}}
/>
</div>
···
const PanelButton =
spacepack.findByCode("Masks.PANEL_BUTTON")[0].exports.default;
+
export default function ExtensionCard({ uniqueId }: { uniqueId: number }) {
const [tab, setTab] = React.useState(ExtensionPage.Info);
const [restartNeeded, setRestartNeeded] = React.useState(false);
+
const { ext, enabled, busy, update, conflicting } = Flux.useStateFromStores(
[MoonbaseSettingsStore],
() => {
return {
+
ext: MoonbaseSettingsStore.getExtension(uniqueId),
+
enabled: MoonbaseSettingsStore.getExtensionEnabled(uniqueId),
busy: MoonbaseSettingsStore.busy,
+
update: MoonbaseSettingsStore.getExtensionUpdate(uniqueId),
+
conflicting: MoonbaseSettingsStore.getExtensionConflicting(uniqueId)
};
}
);
···
<Button
color={Button.Colors.BRAND}
submitting={busy}
+
disabled={conflicting}
onClick={() => {
+
MoonbaseSettingsStore.installExtension(uniqueId);
}}
>
Install
···
icon={TrashIcon}
tooltipText="Delete"
onClick={() => {
+
MoonbaseSettingsStore.deleteExtension(uniqueId);
}}
/>
)}
···
icon={DownloadIcon}
tooltipText="Update"
onClick={() => {
+
MoonbaseSettingsStore.installExtension(uniqueId);
}}
/>
)}
···
checked={enabled}
onChange={() => {
setRestartNeeded(true);
+
MoonbaseSettingsStore.setExtensionEnabled(uniqueId, !enabled);
}}
/>
</div>
+6 -5
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/index.tsx
···
.exports.default;
export default function ExtensionsPage() {
const { extensions, savedFilter } = Flux.useStateFromStoresObject(
[MoonbaseSettingsStore],
() => {
return {
extensions: MoonbaseSettingsStore.extensions,
savedFilter: MoonbaseSettingsStore.getExtensionConfig(
-
"moonbase",
"filter"
)
};
···
if (moonlight.getConfigOption<boolean>("moonbase", "saveFilter")) {
filter = savedFilter ?? defaultFilter;
setFilter = (filter) =>
-
MoonbaseSettingsStore.setExtensionConfig("moonbase", "filter", filter);
} else {
const state = React.useState(defaultFilter);
filter = state[0];
···
(!(filter & Filter.Developer) &&
ext.source.type === ExtensionLoadSource.Developer) ||
(!(filter & Filter.Enabled) &&
-
MoonbaseSettingsStore.getExtensionEnabled(ext.id)) ||
(!(filter & Filter.Disabled) &&
-
!MoonbaseSettingsStore.getExtensionEnabled(ext.id)) ||
(!(filter & Filter.Installed) &&
ext.state !== ExtensionState.NotDownloaded) ||
(!(filter & Filter.Repository) &&
···
/>
</React.Suspense>
{filtered.map((ext) => (
-
<ExtensionCard id={ext.id} key={ext.id} />
))}
</>
);
···
.exports.default;
export default function ExtensionsPage() {
+
const moonbaseId = MoonbaseSettingsStore.getExtensionUniqueId("moonbase")!;
const { extensions, savedFilter } = Flux.useStateFromStoresObject(
[MoonbaseSettingsStore],
() => {
return {
extensions: MoonbaseSettingsStore.extensions,
savedFilter: MoonbaseSettingsStore.getExtensionConfig(
+
moonbaseId,
"filter"
)
};
···
if (moonlight.getConfigOption<boolean>("moonbase", "saveFilter")) {
filter = savedFilter ?? defaultFilter;
setFilter = (filter) =>
+
MoonbaseSettingsStore.setExtensionConfig(moonbaseId, "filter", filter);
} else {
const state = React.useState(defaultFilter);
filter = state[0];
···
(!(filter & Filter.Developer) &&
ext.source.type === ExtensionLoadSource.Developer) ||
(!(filter & Filter.Enabled) &&
+
MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
(!(filter & Filter.Disabled) &&
+
!MoonbaseSettingsStore.getExtensionEnabled(ext.uniqueId)) ||
(!(filter & Filter.Installed) &&
ext.state !== ExtensionState.NotDownloaded) ||
(!(filter & Filter.Repository) &&
···
/>
</React.Suspense>
{filtered.map((ext) => (
+
<ExtensionCard uniqueId={ext.uniqueId} key={ext.id} />
))}
</>
);
+5 -1
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/info.tsx
···
[DependencyType.Incompatible]: "var(--red-400)"
};
const color = colors[dep.type];
-
const name = MoonbaseSettingsStore.getExtensionName(dep.id);
return (
<Badge color={color} key={dep.id}>
{name}
···
[DependencyType.Incompatible]: "var(--red-400)"
};
const color = colors[dep.type];
+
const id = MoonbaseSettingsStore.getExtensionUniqueId(dep.id);
+
const name =
+
(id !== null
+
? MoonbaseSettingsStore.getExtensionName(id!)
+
: null) ?? dep.id;
return (
<Badge color={color} key={dep.id}>
{name}
+24 -21
packages/core-extensions/src/moonbase/webpackModules/ui/extensions/settings.tsx
···
const Margins = spacepack.findByCode("marginCenterHorz:")[0].exports;
-
function useConfigEntry<T>(id: string, name: string) {
return Flux.useStateFromStores(
[MoonbaseSettingsStore],
() => {
return {
-
value: MoonbaseSettingsStore.getExtensionConfig<T>(id, name),
-
displayName: MoonbaseSettingsStore.getExtensionConfigName(id, name),
description: MoonbaseSettingsStore.getExtensionConfigDescription(
-
id,
name
)
};
},
-
[id, name]
);
}
function Boolean({ ext, name, setting, disabled }: SettingsProps) {
const { FormSwitch } = CommonComponents;
const { value, displayName, description } = useConfigEntry<boolean>(
-
ext.id,
name
);
···
hideBorder={true}
disabled={disabled}
onChange={(value: boolean) => {
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
}}
note={description}
className={`${Margins.marginReset} ${Margins.marginTop20}`}
···
function Number({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, Slider } = CommonComponents;
const { value, displayName, description } = useConfigEntry<number>(
-
ext.id,
name
);
···
maxValue={castedSetting.max ?? 100}
onValueChange={(value: number) => {
const rounded = Math.max(min, Math.min(max, Math.round(value)));
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, rounded);
}}
/>
</FormItem>
···
function String({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string>(
-
ext.id,
name
);
···
value={value ?? ""}
onChange={(value: string) => {
if (disabled) return;
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
}}
/>
</FormItem>
···
function MultilineString({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextArea } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string>(
-
ext.id,
name
);
···
className={"moonbase-resizeable"}
onChange={(value: string) => {
if (disabled) return;
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
}}
/>
</FormItem>
···
function Select({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, SingleSelect } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string>(
-
ext.id,
name
);
···
)}
onChange={(value: string) => {
if (disabled) return;
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, value);
}}
/>
</FormItem>
···
const { FormItem, FormText, Select, useVariableSelect, multiSelect } =
CommonComponents;
const { value, displayName, description } = useConfigEntry<string | string[]>(
-
ext.id,
name
);
···
onChange: (value: string) => {
if (disabled) return;
MoonbaseSettingsStore.setExtensionConfig(
-
ext.id,
name,
Array.from(value)
);
···
function List({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput, Button, Flex } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string[]>(
-
ext.id,
name
);
const entries = value ?? [];
const updateConfig = () =>
-
MoonbaseSettingsStore.setExtensionConfig(ext.id, name, entries);
return (
<FormItem className={Margins.marginTop20} title={displayName}>
···
const { FormItem, FormText, TextInput, Button, Flex } = CommonComponents;
const { value, displayName, description } = useConfigEntry<
Record<string, string>
-
>(ext.id, name);
const entries = Object.entries(value ?? {});
const updateConfig = () =>
MoonbaseSettingsStore.setExtensionConfig(
-
ext.id,
name,
Object.fromEntries(entries)
);
···
const Margins = spacepack.findByCode("marginCenterHorz:")[0].exports;
+
function useConfigEntry<T>(uniqueId: number, name: string) {
return Flux.useStateFromStores(
[MoonbaseSettingsStore],
() => {
return {
+
value: MoonbaseSettingsStore.getExtensionConfig<T>(uniqueId, name),
+
displayName: MoonbaseSettingsStore.getExtensionConfigName(
+
uniqueId,
+
name
+
),
description: MoonbaseSettingsStore.getExtensionConfigDescription(
+
uniqueId,
name
)
};
},
+
[uniqueId, name]
);
}
function Boolean({ ext, name, setting, disabled }: SettingsProps) {
const { FormSwitch } = CommonComponents;
const { value, displayName, description } = useConfigEntry<boolean>(
+
ext.uniqueId,
name
);
···
hideBorder={true}
disabled={disabled}
onChange={(value: boolean) => {
+
MoonbaseSettingsStore.setExtensionConfig(ext.uniqueId, name, value);
}}
note={description}
className={`${Margins.marginReset} ${Margins.marginTop20}`}
···
function Number({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, Slider } = CommonComponents;
const { value, displayName, description } = useConfigEntry<number>(
+
ext.uniqueId,
name
);
···
maxValue={castedSetting.max ?? 100}
onValueChange={(value: number) => {
const rounded = Math.max(min, Math.min(max, Math.round(value)));
+
MoonbaseSettingsStore.setExtensionConfig(ext.uniqueId, name, rounded);
}}
/>
</FormItem>
···
function String({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string>(
+
ext.uniqueId,
name
);
···
value={value ?? ""}
onChange={(value: string) => {
if (disabled) return;
+
MoonbaseSettingsStore.setExtensionConfig(ext.uniqueId, name, value);
}}
/>
</FormItem>
···
function MultilineString({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextArea } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string>(
+
ext.uniqueId,
name
);
···
className={"moonbase-resizeable"}
onChange={(value: string) => {
if (disabled) return;
+
MoonbaseSettingsStore.setExtensionConfig(ext.uniqueId, name, value);
}}
/>
</FormItem>
···
function Select({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, SingleSelect } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string>(
+
ext.uniqueId,
name
);
···
)}
onChange={(value: string) => {
if (disabled) return;
+
MoonbaseSettingsStore.setExtensionConfig(ext.uniqueId, name, value);
}}
/>
</FormItem>
···
const { FormItem, FormText, Select, useVariableSelect, multiSelect } =
CommonComponents;
const { value, displayName, description } = useConfigEntry<string | string[]>(
+
ext.uniqueId,
name
);
···
onChange: (value: string) => {
if (disabled) return;
MoonbaseSettingsStore.setExtensionConfig(
+
ext.uniqueId,
name,
Array.from(value)
);
···
function List({ ext, name, setting, disabled }: SettingsProps) {
const { FormItem, FormText, TextInput, Button, Flex } = CommonComponents;
const { value, displayName, description } = useConfigEntry<string[]>(
+
ext.uniqueId,
name
);
const entries = value ?? [];
const updateConfig = () =>
+
MoonbaseSettingsStore.setExtensionConfig(ext.uniqueId, name, entries);
return (
<FormItem className={Margins.marginTop20} title={displayName}>
···
const { FormItem, FormText, TextInput, Button, Flex } = CommonComponents;
const { value, displayName, description } = useConfigEntry<
Record<string, string>
+
>(ext.uniqueId, name);
const entries = Object.entries(value ?? {});
const updateConfig = () =>
MoonbaseSettingsStore.setExtensionConfig(
+
ext.uniqueId,
name,
Object.fromEntries(entries)
);