aboutsummaryrefslogtreecommitdiffstats
path: root/ui/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/state')
-rw-r--r--ui/src/state/store.ts124
1 files changed, 121 insertions, 3 deletions
diff --git a/ui/src/state/store.ts b/ui/src/state/store.ts
index cde2da17..c6d3c152 100644
--- a/ui/src/state/store.ts
+++ b/ui/src/state/store.ts
@@ -19,11 +19,24 @@ import { invoke } from "@tauri-apps/api/core";
import { sessionToken, settings } from "./client";
import { getWeekInfo } from "@/lib/utils";
import Runbook from "./runbooks/runbook";
+import { Terminal } from "@xterm/xterm";
+import { FitAddon } from "@xterm/addon-fit";
+import { WebglAddon } from "@xterm/addon-webgl";
+
+export class TerminalData {
+ terminal: Terminal;
+ fitAddon: FitAddon;
+
+ constructor(terminal: Terminal, fit: FitAddon) {
+ this.terminal = terminal;
+ this.fitAddon = fit;
+ }
+}
// I'll probs want to slice this up at some point, but for now a
// big blobby lump of state is fine.
// Totally just hoping that structure will be emergent in the future.
-interface AtuinState {
+export interface AtuinState {
user: User;
homeInfo: HomeInfo;
aliases: Alias[];
@@ -32,7 +45,7 @@ interface AtuinState {
calendar: any[];
weekStart: number;
runbooks: Runbook[];
- currentRunbook: String | null;
+ currentRunbook: string | null;
refreshHomeInfo: () => void;
refreshCalendar: () => void;
@@ -44,6 +57,16 @@ interface AtuinState {
historyNextPage: (query?: string) => void;
setCurrentRunbook: (id: String) => void;
+ setPtyTerm: (pty: string, terminal: any) => void;
+ newPtyTerm: (pty: string, runbook: string) => TerminalData;
+ cleanupPtyTerm: (pty: string) => void;
+
+ terminals: { [pty: string]: TerminalData };
+
+ // Store ephemeral state for runbooks, that is not persisted to the database
+ runbookInfo: { [runbook: string]: { ptys: number } };
+ incRunbookPty: (runbook: string) => void;
+ decRunbookPty: (runbook: string) => void;
}
let state = (set: any, get: any): AtuinState => ({
@@ -55,6 +78,8 @@ let state = (set: any, get: any): AtuinState => ({
calendar: [],
runbooks: [],
currentRunbook: "",
+ terminals: {},
+ runbookInfo: {},
weekStart: getWeekInfo().firstDay,
@@ -158,8 +183,101 @@ let state = (set: any, get: any): AtuinState => ({
setCurrentRunbook: (id: String) => {
set({ currentRunbook: id });
},
+
+ setPtyTerm: (pty: string, terminal: TerminalData) => {
+ set({
+ terminals: { ...get().terminals, [pty]: terminal },
+ });
+ },
+
+ cleanupPtyTerm: (pty: string) => {
+ set((state: AtuinState) => {
+ const terminals = Object.keys(state.terminals).reduce(
+ (terms: { [pty: string]: TerminalData }, key) => {
+ if (key !== pty) {
+ terms[key] = state.terminals[key];
+ }
+ return terms;
+ },
+ {},
+ );
+
+ return { terminals };
+ });
+ },
+
+ newPtyTerm: (pty: string) => {
+ let terminal = new Terminal();
+
+ // TODO: fallback to canvas, also some sort of setting to allow disabling webgl usage
+ // probs fine for now though, it's widely supported. maybe issues on linux.
+ terminal.loadAddon(new WebglAddon());
+
+ let fitAddon = new FitAddon();
+ terminal.loadAddon(fitAddon);
+
+ const onResize = (size: { cols: number; rows: number }) => {
+ invoke("pty_resize", {
+ pid: pty,
+ cols: size.cols,
+ rows: size.rows,
+ });
+ };
+
+ terminal.onResize(onResize);
+
+ let td = new TerminalData(terminal, fitAddon);
+
+ set({
+ terminals: { ...get().terminals, [pty]: td },
+ });
+
+ return td;
+ },
+
+ incRunbookPty: (runbook: string) => {
+ set((state: AtuinState) => {
+ let oldVal = state.runbookInfo[runbook] || { ptys: 0 };
+ let newVal = { ptys: oldVal.ptys + 1 };
+ console.log(newVal);
+
+ return {
+ runbookInfo: {
+ ...state.runbookInfo,
+ [runbook]: newVal,
+ },
+ };
+ });
+ },
+
+ decRunbookPty: (runbook: string) => {
+ set((state: AtuinState) => {
+ let newVal = state.runbookInfo[runbook];
+ if (!newVal) {
+ return;
+ }
+
+ newVal.ptys--;
+
+ return {
+ runbookInfo: {
+ ...state.runbookInfo,
+ [runbook]: newVal,
+ },
+ };
+ });
+ },
});
export const useStore = create<AtuinState>()(
- persist(state, { name: "atuin-storage" }),
+ persist(state, {
+ name: "atuin-storage",
+
+ // don't serialize the terminals map
+ // it won't work as JSON. too cyclical
+ partialize: (state) =>
+ Object.fromEntries(
+ Object.entries(state).filter(([key]) => !["terminals"].includes(key)),
+ ),
+ }),
);