- Implemented functionality for restoring soft-deleted teams and permanently deleting teams from the system. - Introduced new IPC channels for team restoration and permanent deletion, enhancing team management capabilities. - Updated TeamDataService and related components to handle the new operations, ensuring data integrity during team management. - Enhanced UI components to support team restoration and deletion actions, improving user experience and management workflows.
96 lines
2.7 KiB
TypeScript
96 lines
2.7 KiB
TypeScript
import React, { useEffect, useRef } from 'react';
|
|
|
|
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
|
|
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
|
|
import { json } from '@codemirror/lang-json';
|
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
|
import { EditorState } from '@codemirror/state';
|
|
import { oneDark } from '@codemirror/theme-one-dark';
|
|
import { EditorView, keymap, lineNumbers } from '@codemirror/view';
|
|
|
|
interface MembersJsonEditorProps {
|
|
value: string;
|
|
onChange: (json: string) => void;
|
|
error: string | null;
|
|
}
|
|
|
|
export const MembersJsonEditor = ({
|
|
value,
|
|
onChange,
|
|
error,
|
|
}: MembersJsonEditorProps): React.JSX.Element => {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const viewRef = useRef<EditorView | null>(null);
|
|
const onChangeRef = useRef(onChange);
|
|
onChangeRef.current = onChange;
|
|
|
|
useEffect(() => {
|
|
if (!containerRef.current) return;
|
|
|
|
const state = EditorState.create({
|
|
doc: value,
|
|
extensions: [
|
|
json(),
|
|
oneDark,
|
|
lineNumbers(),
|
|
history(),
|
|
bracketMatching(),
|
|
closeBrackets(),
|
|
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
keymap.of([...defaultKeymap, ...historyKeymap, ...closeBracketsKeymap]),
|
|
EditorView.updateListener.of((update) => {
|
|
if (update.docChanged) {
|
|
onChangeRef.current(update.state.doc.toString());
|
|
}
|
|
}),
|
|
EditorView.theme({
|
|
'&': {
|
|
fontSize: '12px',
|
|
maxHeight: '300px',
|
|
},
|
|
'.cm-scroller': {
|
|
overflow: 'auto',
|
|
},
|
|
'.cm-content': {
|
|
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace',
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
|
|
const view = new EditorView({
|
|
state,
|
|
parent: containerRef.current,
|
|
});
|
|
|
|
viewRef.current = view;
|
|
|
|
return () => {
|
|
view.destroy();
|
|
viewRef.current = null;
|
|
};
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- EditorView created once on mount
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const view = viewRef.current;
|
|
if (!view) return;
|
|
|
|
const currentDoc = view.state.doc.toString();
|
|
if (currentDoc !== value) {
|
|
view.dispatch({
|
|
changes: { from: 0, to: currentDoc.length, insert: value },
|
|
});
|
|
}
|
|
}, [value]);
|
|
|
|
return (
|
|
<div className="space-y-1">
|
|
<div
|
|
ref={containerRef}
|
|
className="overflow-hidden rounded border border-[var(--color-border)]"
|
|
/>
|
|
{error ? <p className="text-[11px] text-red-300">{error}</p> : null}
|
|
</div>
|
|
);
|
|
};
|