mirror of
https://github.com/ByteAtATime/raycast-linux.git
synced 2025-08-31 19:27:24 +00:00
feat: implement preferences management for plugins
Added functionality to manage plugin preferences, including getting and setting preferences through the sidecar. Introduced a PreferencesStore to handle preference persistence and retrieval. Updated relevant components to support preference interactions, enhancing user experience in plugin settings.
This commit is contained in:
parent
09486045c8
commit
3e0fb8fca3
9 changed files with 417 additions and 11 deletions
|
@ -72,13 +72,32 @@ const LogMessageSchema = z.object({
|
|||
export const SidecarMessageSchema = z.union([BatchUpdateSchema, CommandSchema, LogMessageSchema]);
|
||||
export type SidecarMessage = z.infer<typeof SidecarMessageSchema>;
|
||||
|
||||
export const PreferenceSchema = z.object({
|
||||
name: z.string(),
|
||||
title: z.string(),
|
||||
description: z.string().optional(),
|
||||
type: z.enum(['textfield', 'dropdown', 'checkbox', 'directory']),
|
||||
required: z.boolean().optional(),
|
||||
default: z.union([z.string(), z.boolean()]).optional(),
|
||||
data: z
|
||||
.array(
|
||||
z.object({
|
||||
title: z.string(),
|
||||
value: z.string()
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
});
|
||||
export type Preference = z.infer<typeof PreferenceSchema>;
|
||||
|
||||
export const PluginInfoSchema = z.object({
|
||||
title: z.string(),
|
||||
description: z.string().optional(),
|
||||
pluginName: z.string(),
|
||||
commandName: z.string(),
|
||||
pluginPath: z.string(),
|
||||
icon: z.string().optional()
|
||||
icon: z.string().optional(),
|
||||
preferences: z.array(PreferenceSchema).optional()
|
||||
});
|
||||
export type PluginInfo = z.infer<typeof PluginInfoSchema>;
|
||||
|
||||
|
@ -88,6 +107,15 @@ export const PluginListSchema = z.object({
|
|||
});
|
||||
export type PluginList = z.infer<typeof PluginListSchema>;
|
||||
|
||||
export const PreferenceValuesSchema = z.object({
|
||||
type: z.literal('preference-values'),
|
||||
payload: z.object({
|
||||
pluginName: z.string(),
|
||||
values: z.record(z.string(), z.unknown())
|
||||
})
|
||||
});
|
||||
export type PreferenceValues = z.infer<typeof PreferenceValuesSchema>;
|
||||
|
||||
export const GoBackToPluginListSchema = z.object({
|
||||
type: z.literal('go-back-to-plugin-list'),
|
||||
payload: z.object({})
|
||||
|
@ -99,6 +127,7 @@ export const SidecarMessageWithPluginsSchema = z.union([
|
|||
CommandSchema,
|
||||
LogMessageSchema,
|
||||
PluginListSchema,
|
||||
PreferenceValuesSchema,
|
||||
GoBackToPluginListSchema
|
||||
]);
|
||||
export type SidecarMessageWithPlugins = z.infer<typeof SidecarMessageWithPluginsSchema>;
|
||||
|
|
|
@ -11,6 +11,26 @@ import { Form } from './components/form';
|
|||
import { Action, ActionPanel } from './components/actions';
|
||||
import { Detail } from './components/detail';
|
||||
import { environment, getSelectedFinderItems, getSelectedText } from './environment';
|
||||
import { preferencesStore } from '../preferences';
|
||||
|
||||
let currentPluginName: string | null = null;
|
||||
let currentPluginPreferences: Array<{
|
||||
name: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
type: 'textfield' | 'dropdown' | 'checkbox' | 'directory';
|
||||
required?: boolean;
|
||||
default?: string | boolean;
|
||||
data?: Array<{ title: string; value: string }>;
|
||||
}> = [];
|
||||
|
||||
export const setCurrentPlugin = (
|
||||
pluginName: string,
|
||||
preferences?: typeof currentPluginPreferences
|
||||
) => {
|
||||
currentPluginName = pluginName;
|
||||
currentPluginPreferences = preferences || [];
|
||||
};
|
||||
|
||||
export const getRaycastApi = () => {
|
||||
const LocalStorage = createLocalStorage();
|
||||
|
@ -25,12 +45,17 @@ export const getRaycastApi = () => {
|
|||
showToast: () => {},
|
||||
Toast,
|
||||
environment,
|
||||
getPreferenceValues: () => ({
|
||||
getPreferenceValues: () => {
|
||||
if (currentPluginName) {
|
||||
return preferencesStore.getPreferenceValues(currentPluginName, currentPluginPreferences);
|
||||
}
|
||||
return {
|
||||
lang1: 'en',
|
||||
lang2: 'zh-CN',
|
||||
autoInput: true,
|
||||
defaultAction: 'copy'
|
||||
}),
|
||||
};
|
||||
},
|
||||
usePersistentState: <T>(
|
||||
key: string,
|
||||
initialValue: T
|
||||
|
|
|
@ -3,6 +3,7 @@ import { writeLog, writeOutput } from './io';
|
|||
import { runPlugin, sendPluginList } from './plugin';
|
||||
import { instances, navigationStack } from './state';
|
||||
import { batchedUpdates, updateContainer } from './reconciler';
|
||||
import { preferencesStore } from './preferences';
|
||||
import type { RaycastInstance } from './types';
|
||||
|
||||
process.on('unhandledRejection', (reason: unknown) => {
|
||||
|
@ -30,6 +31,26 @@ rl.on('line', (line) => {
|
|||
runPlugin(pluginPath);
|
||||
break;
|
||||
}
|
||||
case 'get-preferences': {
|
||||
const { pluginName } = command.payload as { pluginName: string };
|
||||
const preferences = preferencesStore.getAllPreferences();
|
||||
writeOutput({
|
||||
type: 'preference-values',
|
||||
payload: {
|
||||
pluginName,
|
||||
values: preferences[pluginName] || {}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'set-preferences': {
|
||||
const { pluginName, values } = command.payload as {
|
||||
pluginName: string;
|
||||
values: Record<string, unknown>;
|
||||
};
|
||||
preferencesStore.setPreferenceValues(pluginName, values);
|
||||
break;
|
||||
}
|
||||
case 'pop-view': {
|
||||
const previousElement = navigationStack.pop();
|
||||
if (previousElement) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { updateContainer } from './reconciler';
|
||||
import { writeLog, writeOutput } from './io';
|
||||
import { getRaycastApi } from './api';
|
||||
import { getRaycastApi, setCurrentPlugin } from './api';
|
||||
import { inspect } from 'util';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
@ -63,6 +63,15 @@ export const discoverPlugins = (): PluginInfo[] => {
|
|||
icon?: string;
|
||||
subtitle?: string;
|
||||
}>;
|
||||
preferences?: Array<{
|
||||
name: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
type: 'textfield' | 'dropdown' | 'checkbox' | 'directory';
|
||||
required?: boolean;
|
||||
default?: string | boolean;
|
||||
data?: Array<{ title: string; value: string }>;
|
||||
}>;
|
||||
} = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||
|
||||
const commands = packageJson.commands || [];
|
||||
|
@ -78,7 +87,8 @@ export const discoverPlugins = (): PluginInfo[] => {
|
|||
pluginName: packageJson.name || pluginDirName,
|
||||
commandName: command.name,
|
||||
pluginPath: commandFilePath,
|
||||
icon: command.icon || packageJson.icon
|
||||
icon: command.icon || packageJson.icon,
|
||||
preferences: packageJson.preferences
|
||||
});
|
||||
} else {
|
||||
writeLog(`Command file ${commandFilePath} not found for command ${command.name}`);
|
||||
|
@ -111,9 +121,33 @@ export const loadPlugin = (pluginPath: string): string => {
|
|||
|
||||
export const runPlugin = (pluginPath?: string): void => {
|
||||
let scriptText: string;
|
||||
let pluginName = 'unknown';
|
||||
let preferences: Array<{
|
||||
name: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
type: 'textfield' | 'dropdown' | 'checkbox' | 'directory';
|
||||
required?: boolean;
|
||||
default?: string | boolean;
|
||||
data?: Array<{ title: string; value: string }>;
|
||||
}> = [];
|
||||
|
||||
if (pluginPath) {
|
||||
scriptText = loadPlugin(pluginPath);
|
||||
|
||||
// Extract plugin info from path to set preferences context
|
||||
const pluginDir = path.dirname(pluginPath);
|
||||
const packageJsonPath = path.join(pluginDir, 'package.json');
|
||||
|
||||
if (fs.existsSync(packageJsonPath)) {
|
||||
try {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||
pluginName = packageJson.name || path.basename(pluginDir);
|
||||
preferences = packageJson.preferences || [];
|
||||
} catch (error) {
|
||||
writeLog(`Error reading plugin package.json: ${error}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const fallbackPluginsDir = path.join(
|
||||
process.env.HOME || '/tmp',
|
||||
|
@ -123,16 +157,21 @@ export const runPlugin = (pluginPath?: string): void => {
|
|||
|
||||
if (fs.existsSync(fallbackPath)) {
|
||||
scriptText = loadPlugin(fallbackPath);
|
||||
pluginName = 'google-translate';
|
||||
} else {
|
||||
const oldFallbackPath = path.join(__dirname, '../dist/plugin/translate-form.txt');
|
||||
if (fs.existsSync(oldFallbackPath)) {
|
||||
scriptText = loadPlugin(oldFallbackPath);
|
||||
pluginName = 'translate-fallback';
|
||||
} else {
|
||||
throw new Error('No plugin specified and no fallback plugin found');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the current plugin context for preferences
|
||||
setCurrentPlugin(pluginName, preferences);
|
||||
|
||||
const pluginModule = {
|
||||
exports: {} as { default: React.ComponentType | null }
|
||||
};
|
||||
|
|
72
sidecar/src/preferences.ts
Normal file
72
sidecar/src/preferences.ts
Normal file
|
@ -0,0 +1,72 @@
|
|||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { writeLog } from './io';
|
||||
import type { Preference } from '@raycast-linux/protocol';
|
||||
|
||||
export class PreferencesStore {
|
||||
private preferencesPath: string;
|
||||
private preferences: Record<string, Record<string, unknown>> = {};
|
||||
|
||||
constructor() {
|
||||
const preferencesDir = path.join(process.env.HOME || '/tmp', '.local/share/raycast-linux');
|
||||
this.preferencesPath = path.join(preferencesDir, 'preferences.json');
|
||||
this.loadPreferences();
|
||||
}
|
||||
|
||||
private loadPreferences(): void {
|
||||
try {
|
||||
if (fs.existsSync(this.preferencesPath)) {
|
||||
const data = fs.readFileSync(this.preferencesPath, 'utf-8');
|
||||
this.preferences = JSON.parse(data);
|
||||
}
|
||||
} catch (error) {
|
||||
writeLog(`Error loading preferences: ${error}`);
|
||||
this.preferences = {};
|
||||
}
|
||||
}
|
||||
|
||||
private savePreferences(): void {
|
||||
try {
|
||||
const dir = path.dirname(this.preferencesPath);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
fs.writeFileSync(this.preferencesPath, JSON.stringify(this.preferences, null, 2));
|
||||
} catch (error) {
|
||||
writeLog(`Error saving preferences: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
public getPreferenceValues(
|
||||
pluginName: string,
|
||||
preferenceDefinitions?: Preference[]
|
||||
): Record<string, unknown> {
|
||||
const pluginPrefs = this.preferences[pluginName] || {};
|
||||
const result: Record<string, unknown> = {};
|
||||
|
||||
if (preferenceDefinitions) {
|
||||
for (const pref of preferenceDefinitions) {
|
||||
if (pluginPrefs[pref.name] !== undefined) {
|
||||
result[pref.name] = pluginPrefs[pref.name];
|
||||
} else if (pref.default !== undefined) {
|
||||
result[pref.name] = pref.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public setPreferenceValues(pluginName: string, values: Record<string, unknown>): void {
|
||||
if (!this.preferences[pluginName]) {
|
||||
this.preferences[pluginName] = {};
|
||||
}
|
||||
|
||||
Object.assign(this.preferences[pluginName], values);
|
||||
this.savePreferences();
|
||||
}
|
||||
|
||||
public getAllPreferences(): Record<string, Record<string, unknown>> {
|
||||
return { ...this.preferences };
|
||||
}
|
||||
}
|
||||
|
||||
export const preferencesStore = new PreferencesStore();
|
171
src/lib/components/SettingsView.svelte
Normal file
171
src/lib/components/SettingsView.svelte
Normal file
|
@ -0,0 +1,171 @@
|
|||
<script lang="ts">
|
||||
import type { PluginInfo, Preference } from '@raycast-linux/protocol';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
|
||||
type Props = {
|
||||
plugins: PluginInfo[];
|
||||
onBack: () => void;
|
||||
onSavePreferences: (pluginName: string, values: Record<string, unknown>) => void;
|
||||
onGetPreferences: (pluginName: string) => void;
|
||||
currentPreferences: Record<string, unknown>;
|
||||
};
|
||||
|
||||
let { plugins, onBack, onSavePreferences, onGetPreferences, currentPreferences }: Props =
|
||||
$props();
|
||||
|
||||
let selectedPluginIndex = $state(0);
|
||||
let preferenceValues = $state<Record<string, unknown>>({});
|
||||
|
||||
const selectedPlugin = $derived(plugins[selectedPluginIndex]);
|
||||
const pluginsWithPreferences = $derived(
|
||||
plugins.filter((p) => p.preferences && p.preferences.length > 0)
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
if (selectedPlugin) {
|
||||
onGetPreferences(selectedPlugin.pluginName);
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
preferenceValues = { ...currentPreferences };
|
||||
});
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
onBack();
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
selectedPluginIndex = Math.max(0, selectedPluginIndex - 1);
|
||||
} else if (event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
selectedPluginIndex = Math.min(pluginsWithPreferences.length - 1, selectedPluginIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
if (selectedPlugin) {
|
||||
onSavePreferences(selectedPlugin.pluginName, preferenceValues);
|
||||
}
|
||||
}
|
||||
|
||||
function handlePreferenceChange(prefName: string, value: unknown) {
|
||||
preferenceValues = { ...preferenceValues, [prefName]: value };
|
||||
}
|
||||
|
||||
function getPreferenceValue(pref: Preference): unknown {
|
||||
return preferenceValues[pref.name] ?? pref.default ?? '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window onkeydown={handleKeydown} />
|
||||
|
||||
<main class="bg-background text-foreground flex h-screen">
|
||||
<div class="flex w-80 flex-col border-r">
|
||||
<header class="flex h-12 shrink-0 items-center border-b px-4">
|
||||
<button onclick={onBack} class="hover:bg-accent mr-3 rounded p-1">
|
||||
<Icon icon="chevron-left-16" class="size-4" />
|
||||
</button>
|
||||
<h1 class="font-medium">Extension Settings</h1>
|
||||
</header>
|
||||
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
{#each pluginsWithPreferences as plugin, index}
|
||||
<button
|
||||
type="button"
|
||||
class="hover:bg-accent/50 flex w-full items-center gap-3 px-4 py-3 text-left"
|
||||
class:bg-accent={selectedPluginIndex === index}
|
||||
onclick={() => (selectedPluginIndex = index)}
|
||||
>
|
||||
<div class="flex size-8 shrink-0 items-center justify-center">
|
||||
<Icon icon={plugin.icon || 'app-window-16'} class="size-5" />
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-medium">{plugin.title}</span>
|
||||
<span class="text-muted-foreground text-xs">{plugin.pluginName}</span>
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1 flex-col">
|
||||
{#if selectedPlugin && selectedPlugin.preferences}
|
||||
<header class="flex h-12 shrink-0 items-center justify-between border-b px-6">
|
||||
<div>
|
||||
<h2 class="font-medium">{selectedPlugin.title}</h2>
|
||||
<p class="text-muted-foreground text-sm">{selectedPlugin.description}</p>
|
||||
</div>
|
||||
<button
|
||||
onclick={handleSave}
|
||||
class="bg-primary text-primary-foreground hover:bg-primary/90 rounded px-4 py-2 text-sm"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="flex-1 overflow-y-auto p-6">
|
||||
<div class="max-w-md space-y-6">
|
||||
{#each selectedPlugin.preferences as pref}
|
||||
<div class="space-y-2">
|
||||
<label class="text-sm font-medium">
|
||||
{pref.title}
|
||||
{#if pref.required}<span class="text-red-500">*</span>{/if}
|
||||
</label>
|
||||
|
||||
{#if pref.description}
|
||||
<p class="text-muted-foreground text-xs">{pref.description}</p>
|
||||
{/if}
|
||||
|
||||
{#if pref.type === 'textfield'}
|
||||
<Input
|
||||
value={getPreferenceValue(pref) as string}
|
||||
onchange={(e) =>
|
||||
handlePreferenceChange(pref.name, (e.target as HTMLInputElement)?.value)}
|
||||
placeholder={pref.default as string}
|
||||
/>
|
||||
{:else if pref.type === 'checkbox'}
|
||||
<label class="flex items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={getPreferenceValue(pref) as boolean}
|
||||
onchange={(e) =>
|
||||
handlePreferenceChange(pref.name, (e.target as HTMLInputElement)?.checked)}
|
||||
class="rounded"
|
||||
/>
|
||||
<span class="text-sm">Enable</span>
|
||||
</label>
|
||||
{:else if pref.type === 'dropdown' && pref.data}
|
||||
<select
|
||||
value={getPreferenceValue(pref) as string}
|
||||
onchange={(e) =>
|
||||
handlePreferenceChange(pref.name, (e.target as HTMLSelectElement)?.value)}
|
||||
class="bg-background border-border w-full rounded border px-3 py-2 text-sm"
|
||||
>
|
||||
{#each pref.data as option}
|
||||
<option value={option.value}>{option.title}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else if pref.type === 'directory'}
|
||||
<Input
|
||||
value={getPreferenceValue(pref) as string}
|
||||
onchange={(e) =>
|
||||
handlePreferenceChange(pref.name, (e.target as HTMLInputElement)?.value)}
|
||||
placeholder={pref.default as string}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-1 items-center justify-center">
|
||||
<div class="text-center">
|
||||
<p class="text-muted-foreground">Select a plugin to configure its settings</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</main>
|
|
@ -67,6 +67,14 @@ class SidecarService {
|
|||
this.dispatchEvent('request-plugin-list');
|
||||
};
|
||||
|
||||
getPreferences = (pluginName: string) => {
|
||||
this.dispatchEvent('get-preferences', { pluginName });
|
||||
};
|
||||
|
||||
setPreferences = (pluginName: string, values: Record<string, unknown>) => {
|
||||
this.dispatchEvent('set-preferences', { pluginName, values });
|
||||
};
|
||||
|
||||
#handleStdout = (chunk: Uint8Array) => {
|
||||
try {
|
||||
this.#receiveBuffer = Buffer.concat([this.#receiveBuffer, Buffer.from(chunk)]);
|
||||
|
@ -120,6 +128,11 @@ class SidecarService {
|
|||
return;
|
||||
}
|
||||
|
||||
if (typedMessage.type === 'preference-values') {
|
||||
uiStore.setCurrentPreferences(typedMessage.payload.values);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typedMessage.type === 'go-back-to-plugin-list') {
|
||||
if (this.#onGoBackToPluginList) {
|
||||
this.#onGoBackToPluginList();
|
||||
|
|
|
@ -10,6 +10,7 @@ function createUiStore() {
|
|||
let rootNodeId = $state<number | null>(null);
|
||||
let selectedNodeId = $state<number | undefined>(undefined);
|
||||
let pluginList = $state<PluginInfo[]>([]);
|
||||
let currentPreferences = $state<Record<string, unknown>>({});
|
||||
|
||||
const applyCommands = (commands: Command[]) => {
|
||||
const tempTree = new Map(uiTree);
|
||||
|
@ -48,6 +49,10 @@ function createUiStore() {
|
|||
pluginList = plugins;
|
||||
};
|
||||
|
||||
const setCurrentPreferences = (preferences: Record<string, unknown>) => {
|
||||
currentPreferences = preferences;
|
||||
};
|
||||
|
||||
const resetForNewPlugin = () => {
|
||||
uiTree = new Map();
|
||||
rootNodeId = null;
|
||||
|
@ -156,8 +161,12 @@ function createUiStore() {
|
|||
get pluginList() {
|
||||
return pluginList;
|
||||
},
|
||||
get currentPreferences() {
|
||||
return currentPreferences;
|
||||
},
|
||||
applyCommands,
|
||||
setPluginList,
|
||||
setCurrentPreferences,
|
||||
resetForNewPlugin
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,13 +8,14 @@
|
|||
import Content from '$lib/components/layout/Content.svelte';
|
||||
import Footer from '$lib/components/layout/Footer.svelte';
|
||||
import PluginList from '$lib/components/PluginList.svelte';
|
||||
import SettingsView from '$lib/components/SettingsView.svelte';
|
||||
import type { PluginInfo } from '@raycast-linux/protocol';
|
||||
|
||||
type ViewState = 'plugin-list' | 'plugin-running';
|
||||
type ViewState = 'plugin-list' | 'plugin-running' | 'settings';
|
||||
|
||||
let viewState = $state<ViewState>('plugin-list');
|
||||
|
||||
const { uiTree, rootNodeId, selectedNodeId, pluginList } = $derived(uiStore);
|
||||
const { uiTree, rootNodeId, selectedNodeId, pluginList, currentPreferences } = $derived(uiStore);
|
||||
|
||||
$effect(() => {
|
||||
untrack(() => {
|
||||
|
@ -85,6 +86,12 @@
|
|||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (viewState === 'plugin-list' && event.key === ',' && (event.metaKey || event.ctrlKey)) {
|
||||
event.preventDefault();
|
||||
viewState = 'settings';
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewState !== 'plugin-running') return;
|
||||
|
||||
if (event.key === 'Escape') {
|
||||
|
@ -130,12 +137,32 @@
|
|||
viewState = 'plugin-running';
|
||||
searchText = '';
|
||||
}
|
||||
|
||||
function handleBackToPluginList() {
|
||||
viewState = 'plugin-list';
|
||||
}
|
||||
|
||||
function handleSavePreferences(pluginName: string, values: Record<string, unknown>) {
|
||||
sidecarService.setPreferences(pluginName, values);
|
||||
}
|
||||
|
||||
function handleGetPreferences(pluginName: string) {
|
||||
sidecarService.getPreferences(pluginName);
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window onkeydown={handleKeydown} />
|
||||
|
||||
{#if viewState === 'plugin-list'}
|
||||
<PluginList plugins={pluginList} onRunPlugin={handleRunPlugin} />
|
||||
{:else if viewState === 'settings'}
|
||||
<SettingsView
|
||||
plugins={pluginList}
|
||||
onBack={handleBackToPluginList}
|
||||
onSavePreferences={handleSavePreferences}
|
||||
onGetPreferences={handleGetPreferences}
|
||||
{currentPreferences}
|
||||
/>
|
||||
{:else if viewState === 'plugin-running' && rootNode}
|
||||
<MainLayout>
|
||||
{#snippet header()}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue