Przejdź do głównej zawartości
docs
GitHub

Widoki i zapis stanu

Wybierz miejsce widoku, zapisz niewielki stan JSON i zabezpiecz niezapisane dokumenty.

Widok central otwiera się jako karta i może trafić do podzielonego układu paneli. Przy multiple: false ponowne otwarcie wybiera istniejącą instancję w bieżącym obszarze roboczym. Przy multiple: true każde otwarcie tworzy nową instancję.

Widok sidebar ma jedną instancję na obszar roboczy i wymaga multiple: false. Jego strona oraz szerokość są zapisywane razem z układem. Oba rodzaje wymagają otwartego obszaru roboczego.

Jeśli openView(id, initialState) użyje istniejącej instancji, initialState nie zastąpi zapisanego stanu. Do dalszych zmian służy setState() otrzymane przez widok.

Właściwość Znaczenie
panel Zapisany opis tej instancji widoku.
active Czy widok jest aktywny.
setState(state) Zastępuje stan JSON w opisie panelu.
onFocus() Zgłasza fokus do głównego obszaru aplikacji.
onClose() Prosi aplikację o zamknięcie widoku zwykłą ścieżką.

panel zawiera type: 'plugin', id, title, opcjonalne customTitle, owner, viewType, stateVersion i state.

Używaj zwykłych przycisków, pól i linków. Aplikacja przechwytuje fokus wewnątrz panelu. Własna obsługa może wywołać onFocus(), a atrybut data-plugin-focus może wskazać element dla funkcji skupiania położeniem wskaźnika.

Używaj setState() do wybranego elementu, filtra lub rozwiniętej sekcji. Metoda zastępuje całą wartość JSON, więc przekaż wszystkie pola, które chcesz zachować.

Obsługiwane są null, wartości logiczne, tekst, skończone liczby, tablice i zwykłe obiekty JSON. Funkcje, instancje klas, cykle i zastrzeżone klucze (__proto__, constructor, prototype) są odrzucane.

Limit Wartość
Rozmiar po serializacji do UTF-8 64 KiB
Liczba odwiedzonych wartości 4096
Głębokość zagnieżdżenia 16

Ten stan należy do zapisanej sesji. Nie używaj go jako magazynu niezapisanej zawartości plików.

Ten komponent możesz zarejestrować zamiast widoku szablonu. Odczytuje starszy lub pusty stan z bezpiecznymi wartościami domyślnymi i przy zapisie zachowuje pozostałą opcję:

import type { Json, ViewProps } from '@lomi-dev/plugin-sdk';
type Options = { filter: string; expanded: boolean };
export function readOptions(value: Json): Options {
const object = value && typeof value === 'object' && !Array.isArray(value)
? value : {};
return {
filter: typeof object.filter === 'string' ? object.filter : '',
expanded: typeof object.expanded === 'boolean' ? object.expanded : true,
};
}
export function FilterPanel({ panel, setState }: ViewProps) {
const options = readOptions(panel.state);
return (
<section className="lomi-workspace-info">
<label>
Filter
<input
value={options.filter}
onChange={(event) => setState({ ...options, filter: event.target.value })}
/>
</label>
<button
type="button"
aria-expanded={options.expanded}
onClick={() => setState({ ...options, expanded: !options.expanded })}
>
Details
</button>
{options.expanded && <p>Current filter: {options.filter || 'All'}</p>}
</section>
);
}

setState() przyjmuje gotową wartość, nie funkcję w stylu React setState(previous => ...). Nie zmieniaj bezpośrednio panel.state w działającym pluginie. Każdy panel ma własne ID i własny stan; zmiana aktywnego workspace w useHostContext() nie zamienia tego ID.

Odtwarzany panel jest renderowany tylko wtedy, gdy zadeklarowane stateVersion i placement odpowiadają jego opisowi. Zmiana wersji nie uruchamia migracji: SDK v1 nie udostępnia funkcji migracji stanu.

Przy zgodnym rozszerzeniu pozostaw wersję i ustaw wartości domyślne brakujących pól. Po niezgodnej zmianie istniejące panele pokażą komunikat o niedostępności. Stary stan pozostaje do czasu ich zamknięcia przez użytkownika lub przywrócenia zgodnego kodu.

Przechowuj edytowane dane poza przejściowym komponentem React, pod kluczem będącym ID panelu. Zarejestruj zabezpieczenie raz dla tego panelu:

import type { DirtyView, PluginContext } from '@lomi-dev/plugin-sdk';
export function protectDocument(
context: PluginContext,
panelId: string,
document: DirtyView,
) {
return context.registerDirtyView(panelId, document);
}

Własny obiekt document dostarcza:

  • title: nazwę wyświetlaną przy zamykaniu, do 160 znaków.
  • isDirty(): informację, czy pozostały niezapisane zmiany.
  • save(): obietnicę rozwiązywaną dopiero po udanym zapisie.
  • discard(): jawne porzucenie niezapisanych zmian.

Po zakończeniu save() metoda isDirty() musi zwracać false. Odrzucona obietnica, wyjątek lub nadal niezapisany stan blokują zamknięcie. Panel musi już istnieć i należeć do tego pluginu. Każdy panel może mieć jedno zabezpieczenie.

Utrzymuj zabezpieczenie przez cały czas istnienia panelu, również gdy komponent jest chwilowo odmontowany. Nie wiąż jego życia ze sprzątaniem efektu React, które może wykonać się podczas zmiany układu. Aplikacja usuwa zabezpieczenia zamkniętych paneli i zwalnia rejestracje przy dezaktywacji. Własny magazyn dokumentów i pozostałe zasoby nadal wymagają sprzątania.

Wyłączenie i odinstalowanie pluginu korzysta z tych zabezpieczeń przed usunięciem jego elementów. Anulowanie zamknięcia pozostawia plugin uruchomiony.

Poniższa funkcja buduje zabezpieczenie wokół istniejącego modelu. persist jest Twoją implementacją zapisu, nie metodą SDK. Publiczne SDK nie dostarcza usługi plików.

import type { DirtyView } from '@lomi-dev/plugin-sdk';
type DocumentModel = { title: string; text: string; savedText: string };
export function documentGuard(
model: DocumentModel,
persist: (text: string) => Promise<void>,
): DirtyView {
return {
title: model.title,
isDirty: () => model.text !== model.savedText,
async save() {
const submittedText = model.text;
await persist(submittedText);
model.savedText = submittedText;
},
discard() { model.text = model.savedText; },
};
}

Po uzyskaniu ID przez openView() utwórz lub znajdź model w magazynie pluginu i wywołaj registerDirtyView(panelId, documentGuard(model, persist)) tylko raz. Jeśli treść zmieni się w trakcie zapisu, isDirty() nadal zwróci true, więc host nie zamknie panelu z nową niezapisaną zmianą.

Zabezpieczenie nie zapisuje danych automatycznie ani nie przywraca niezapisanego tekstu po awarii procesu. SDK nie udostępnia również kompletnej listy paneli i zdarzenia zamknięcia każdego panelu. Zaprojektuj ograniczony magazyn dokumentów i jego zwalnianie; usunięcie guardu przez host nie usuwa Twojego modelu.

Metoda onClose() komponentu tylko prosi o zamknięcie. Nie potwierdza, że użytkownik zaakceptował operację, więc nie usuwaj od razu niezapisanych danych. Przypadki zamykania sprawdź w zainstalowanej aplikacji.

Kod źródłowy: renderowanie i zgodność widoków, walidacja stanu, tworzenie paneli.