fix: open ai workspace console in ops
This commit is contained in:
parent
342df60c24
commit
b1d19cf5df
|
|
@ -4,23 +4,13 @@
|
|||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import useSWR from "swr";
|
||||
import { MessageCircle } from "lucide-react";
|
||||
// plane imports
|
||||
import { Tooltip } from "@plane/propel/tooltip";
|
||||
// components
|
||||
import { AIWorkspaceProductSettingsModal } from "@/components/ai-workspace/product-settings-modal";
|
||||
// services
|
||||
import { WorkspaceAIWorkspaceService } from "@/services/workspace-ai-workspace.service";
|
||||
import type {
|
||||
TAIWorkspaceExecutor,
|
||||
TAIWorkspaceExecutorInput,
|
||||
TAIWorkspaceExecutorListResponse,
|
||||
} from "@/services/workspace-ai-workspace.service";
|
||||
|
||||
const workspaceAIWorkspaceService = new WorkspaceAIWorkspaceService();
|
||||
import { AIWorkspaceProductConsole } from "@/components/ai-workspace/product-console";
|
||||
|
||||
type TAIWorkspaceGlobalControlProps = {
|
||||
workspaceSlug: string;
|
||||
|
|
@ -29,15 +19,6 @@ type TAIWorkspaceGlobalControlProps = {
|
|||
export function AIWorkspaceGlobalControl({ workspaceSlug }: TAIWorkspaceGlobalControlProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [dockSlot, setDockSlot] = useState<Element | null>(null);
|
||||
const [busyId, setBusyId] = useState("");
|
||||
const [notice, setNotice] = useState("");
|
||||
const [actionError, setActionError] = useState("");
|
||||
|
||||
const { data, error, isLoading, mutate } = useSWR(
|
||||
isOpen && workspaceSlug ? `AI_WORKSPACE_EXECUTORS_${workspaceSlug}` : null,
|
||||
() => workspaceAIWorkspaceService.listExecutors(workspaceSlug),
|
||||
{ refreshInterval: isOpen ? 10000 : 0 }
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof document === "undefined") return;
|
||||
|
|
@ -58,98 +39,6 @@ export function AIWorkspaceGlobalControl({ workspaceSlug }: TAIWorkspaceGlobalCo
|
|||
};
|
||||
}, []);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
setNotice("");
|
||||
setActionError("");
|
||||
}, []);
|
||||
|
||||
const runMutation = useCallback(
|
||||
async <T,>(id: string, action: () => Promise<T>, successText: string): Promise<T | null> => {
|
||||
setBusyId(id);
|
||||
setActionError("");
|
||||
setNotice("");
|
||||
try {
|
||||
const result = await action();
|
||||
setNotice(successText);
|
||||
return result;
|
||||
} catch (mutationError: any) {
|
||||
setActionError(
|
||||
String(mutationError?.message || mutationError?.error || mutationError || "AI Workspace request failed")
|
||||
);
|
||||
return null;
|
||||
} finally {
|
||||
setBusyId("");
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const updateRegistry = useCallback(
|
||||
async (payload: TAIWorkspaceExecutorListResponse) => {
|
||||
await mutate(payload, { revalidate: false });
|
||||
return payload;
|
||||
},
|
||||
[mutate]
|
||||
);
|
||||
|
||||
const selectExecutor = useCallback(
|
||||
async (executor: TAIWorkspaceExecutor) =>
|
||||
runMutation(
|
||||
`select:${executor.id}`,
|
||||
async () => updateRegistry(await workspaceAIWorkspaceService.selectExecutor(workspaceSlug, executor.id)),
|
||||
"Устройство выбрано"
|
||||
),
|
||||
[runMutation, updateRegistry, workspaceSlug]
|
||||
);
|
||||
|
||||
const createExecutor = useCallback(
|
||||
async (input: TAIWorkspaceExecutorInput) =>
|
||||
runMutation(
|
||||
"save",
|
||||
async () => updateRegistry(await workspaceAIWorkspaceService.createExecutor(workspaceSlug, input)),
|
||||
"Устройство создано"
|
||||
),
|
||||
[runMutation, updateRegistry, workspaceSlug]
|
||||
);
|
||||
|
||||
const updateExecutor = useCallback(
|
||||
async (executorId: string, input: TAIWorkspaceExecutorInput) =>
|
||||
runMutation(
|
||||
"save",
|
||||
async () => updateRegistry(await workspaceAIWorkspaceService.updateExecutor(workspaceSlug, executorId, input)),
|
||||
"Устройство сохранено"
|
||||
),
|
||||
[runMutation, updateRegistry, workspaceSlug]
|
||||
);
|
||||
|
||||
const deleteExecutor = useCallback(
|
||||
async (executorId: string) =>
|
||||
runMutation(
|
||||
`delete:${executorId}`,
|
||||
async () => updateRegistry(await workspaceAIWorkspaceService.deleteExecutor(workspaceSlug, executorId)),
|
||||
"Устройство удалено"
|
||||
),
|
||||
[runMutation, updateRegistry, workspaceSlug]
|
||||
);
|
||||
|
||||
const downloadAgent = useCallback(
|
||||
async (executorId: string, input: TAIWorkspaceExecutorInput, port: string) => {
|
||||
await runMutation(
|
||||
"download",
|
||||
async () => {
|
||||
const payload = await workspaceAIWorkspaceService.updateExecutor(workspaceSlug, executorId, input);
|
||||
await updateRegistry(payload);
|
||||
window.location.href = workspaceAIWorkspaceService.getWindowsAgentInstallerUrl(workspaceSlug, executorId, {
|
||||
port,
|
||||
});
|
||||
},
|
||||
"Installer подготовлен"
|
||||
);
|
||||
},
|
||||
[runMutation, updateRegistry, workspaceSlug]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{dockSlot
|
||||
|
|
@ -168,26 +57,7 @@ export function AIWorkspaceGlobalControl({ workspaceSlug }: TAIWorkspaceGlobalCo
|
|||
)
|
||||
: null}
|
||||
|
||||
<AIWorkspaceProductSettingsModal
|
||||
isOpen={isOpen}
|
||||
executors={data?.executors ?? []}
|
||||
selectedExecutorId={data?.selectedExecutorId ?? null}
|
||||
isLoading={isLoading}
|
||||
error={error}
|
||||
notice={notice}
|
||||
actionError={actionError}
|
||||
busyId={busyId}
|
||||
onClose={handleClose}
|
||||
onReload={() => mutate()}
|
||||
onSelect={selectExecutor}
|
||||
onCreate={createExecutor}
|
||||
onUpdate={updateExecutor}
|
||||
onDelete={deleteExecutor}
|
||||
onDownloadAgent={downloadAgent}
|
||||
getWindowsAgentInstallerUrl={(executorId, options) =>
|
||||
workspaceAIWorkspaceService.getWindowsAgentInstallerUrl(workspaceSlug, executorId, options)
|
||||
}
|
||||
/>
|
||||
<AIWorkspaceProductConsole open={isOpen} workspaceSlug={workspaceSlug} onClose={() => setIsOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -50,6 +50,64 @@ export type TAIWorkspaceExecutorInput = {
|
|||
status?: TAIWorkspaceExecutorStatus;
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThread = {
|
||||
id: string;
|
||||
title: string;
|
||||
originSurface: "engine" | "ops" | "global" | string;
|
||||
activeContext?: Record<string, any>;
|
||||
enabledToolPacks?: string[];
|
||||
linkedArtifacts?: Record<string, any>[];
|
||||
selectedExecutorId?: string | null;
|
||||
lifecycleState?: "active" | "archived" | string;
|
||||
metadata?: Record<string, any>;
|
||||
createdAt?: string | null;
|
||||
updatedAt?: string | null;
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThreadMessageRole = "system" | "user" | "assistant" | "tool";
|
||||
|
||||
export type TAIWorkspaceThreadMessage = {
|
||||
id: string;
|
||||
threadId: string;
|
||||
sequence?: number;
|
||||
role: TAIWorkspaceThreadMessageRole;
|
||||
content: string;
|
||||
payload?: Record<string, any>;
|
||||
createdAt?: string | null;
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThreadListResponse = {
|
||||
ok: boolean;
|
||||
threads: TAIWorkspaceThread[];
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThreadResponse = {
|
||||
ok: boolean;
|
||||
thread: TAIWorkspaceThread;
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThreadMessagesResponse = {
|
||||
ok: boolean;
|
||||
threadId: string;
|
||||
messages: TAIWorkspaceThreadMessage[];
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThreadMessageResponse = {
|
||||
ok: boolean;
|
||||
message: TAIWorkspaceThreadMessage;
|
||||
};
|
||||
|
||||
export type TAIWorkspaceThreadInput = {
|
||||
title: string;
|
||||
originSurface?: "engine" | "ops" | "global";
|
||||
activeContext?: Record<string, any>;
|
||||
enabledToolPacks?: string[];
|
||||
linkedArtifacts?: Record<string, any>[];
|
||||
selectedExecutorId?: string | null;
|
||||
lifecycleState?: "active" | "archived";
|
||||
metadata?: Record<string, any>;
|
||||
};
|
||||
|
||||
export class WorkspaceAIWorkspaceService extends APIService {
|
||||
constructor() {
|
||||
super(API_BASE_URL);
|
||||
|
|
@ -63,10 +121,15 @@ export class WorkspaceAIWorkspaceService extends APIService {
|
|||
});
|
||||
}
|
||||
|
||||
async createExecutor(workspaceSlug: string, input: TAIWorkspaceExecutorInput): Promise<TAIWorkspaceExecutorListResponse> {
|
||||
await this.post(`/api/workspaces/${workspaceSlug}/ai-workspace/executors/`, { ...input, select: true }).catch((error) => {
|
||||
async createExecutor(
|
||||
workspaceSlug: string,
|
||||
input: TAIWorkspaceExecutorInput
|
||||
): Promise<TAIWorkspaceExecutorListResponse> {
|
||||
await this.post(`/api/workspaces/${workspaceSlug}/ai-workspace/executors/`, { ...input, select: true }).catch(
|
||||
(error) => {
|
||||
throw error?.response?.data ?? error;
|
||||
});
|
||||
}
|
||||
);
|
||||
return this.listExecutors(workspaceSlug);
|
||||
}
|
||||
|
||||
|
|
@ -101,4 +164,68 @@ export class WorkspaceAIWorkspaceService extends APIService {
|
|||
if (port) params.set("port", port);
|
||||
return `${API_BASE_URL}/api/workspaces/${workspaceSlug}/ai-workspace/executors/${executorId}/agent/windows.ps1?${params.toString()}`;
|
||||
}
|
||||
|
||||
async listThreads(
|
||||
workspaceSlug: string,
|
||||
options: { surface?: "ops" | "engine" | "global"; limit?: number } = {}
|
||||
): Promise<TAIWorkspaceThreadListResponse> {
|
||||
const params = new URLSearchParams();
|
||||
params.set("surface", options.surface || "ops");
|
||||
params.set("limit", String(options.limit || 100));
|
||||
return this.get(`/api/workspaces/${workspaceSlug}/ai-workspace/threads/?${params.toString()}`)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data ?? error;
|
||||
});
|
||||
}
|
||||
|
||||
async createThread(workspaceSlug: string, input: TAIWorkspaceThreadInput): Promise<TAIWorkspaceThreadResponse> {
|
||||
return this.post(`/api/workspaces/${workspaceSlug}/ai-workspace/threads/`, {
|
||||
originSurface: "ops",
|
||||
enabledToolPacks: ["ops"],
|
||||
...input,
|
||||
})
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data ?? error;
|
||||
});
|
||||
}
|
||||
|
||||
async updateThread(
|
||||
workspaceSlug: string,
|
||||
threadId: string,
|
||||
input: Partial<TAIWorkspaceThreadInput>
|
||||
): Promise<TAIWorkspaceThreadResponse> {
|
||||
return this.patch(`/api/workspaces/${workspaceSlug}/ai-workspace/threads/${threadId}/`, input)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data ?? error;
|
||||
});
|
||||
}
|
||||
|
||||
async listThreadMessages(
|
||||
workspaceSlug: string,
|
||||
threadId: string,
|
||||
options: { limit?: number } = {}
|
||||
): Promise<TAIWorkspaceThreadMessagesResponse> {
|
||||
const params = new URLSearchParams();
|
||||
params.set("limit", String(options.limit || 200));
|
||||
return this.get(`/api/workspaces/${workspaceSlug}/ai-workspace/threads/${threadId}/messages/?${params.toString()}`)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data ?? error;
|
||||
});
|
||||
}
|
||||
|
||||
async createThreadMessage(
|
||||
workspaceSlug: string,
|
||||
threadId: string,
|
||||
input: { role: TAIWorkspaceThreadMessageRole; content: string; payload?: Record<string, any> }
|
||||
): Promise<TAIWorkspaceThreadMessageResponse> {
|
||||
return this.post(`/api/workspaces/${workspaceSlug}/ai-workspace/threads/${threadId}/messages/`, input)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response?.data ?? error;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1307,6 +1307,787 @@
|
|||
}
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console {
|
||||
--ai-console-control-h: 46px;
|
||||
--wf-share-control-h: var(--ai-console-control-h);
|
||||
--brand: rgb(var(--nodedc-card-active-rgb));
|
||||
--brand-rgb: var(--nodedc-card-active-rgb);
|
||||
--brand-contrast: rgb(var(--nodedc-on-card-active-rgb));
|
||||
--nodedc-glass-panel-bg:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.038) 0%, rgba(255, 255, 255, 0.012) 100%), rgba(8, 9, 10, 0.9);
|
||||
--nodedc-glass-control-bg: rgba(255, 255, 255, 0.045);
|
||||
--nodedc-glass-control-hover: rgba(255, 255, 255, 0.078);
|
||||
--nodedc-glass-control-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.055), 0 10px 28px rgba(0, 0, 0, 0.22);
|
||||
--nodedc-glass-panel-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 28px 78px rgba(0, 0, 0, 0.48);
|
||||
--nodedc-glass-outline-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.025));
|
||||
position: fixed;
|
||||
z-index: 26000;
|
||||
display: grid;
|
||||
width: min(1080px, calc(100vw - 104px));
|
||||
height: min(620px, calc(100vh - 84px));
|
||||
min-height: 420px;
|
||||
min-width: 960px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console[data-fullscreen="true"] {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-shell {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
grid-template-columns: var(--ai-threads-width, 330px) 10px minmax(0, 1fr);
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
overflow: hidden;
|
||||
border-radius: 22px;
|
||||
background: var(--nodedc-glass-panel-bg);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
pointer-events: auto;
|
||||
box-shadow: var(--nodedc-glass-panel-shadow);
|
||||
-webkit-backdrop-filter: blur(64px) saturate(150%) brightness(1.08);
|
||||
backdrop-filter: blur(64px) saturate(150%) brightness(1.08);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-shell::after,
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity::after {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 2;
|
||||
border-radius: inherit;
|
||||
padding: 1px;
|
||||
background: var(--nodedc-glass-outline-gradient);
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
-webkit-mask:
|
||||
linear-gradient(#000 0 0) content-box,
|
||||
linear-gradient(#000 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-header,
|
||||
.nodedc-ai-workspace-console .ai-console-actions,
|
||||
.nodedc-ai-workspace-console .ai-console-threads__head,
|
||||
.nodedc-ai-workspace-console .ai-console-composer,
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity__header,
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-header {
|
||||
min-height: var(--ai-console-control-h);
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-topbar {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 1;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-header[data-draggable="true"] {
|
||||
cursor: move;
|
||||
touch-action: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-title-block {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-title-block h2 {
|
||||
margin: 7px 0 0;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: rgba(255, 255, 255, 0.96);
|
||||
font-size: 18px;
|
||||
font-weight: 760;
|
||||
letter-spacing: 0;
|
||||
line-height: 1.15;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-kicker {
|
||||
color: rgba(255, 255, 255, 0.48);
|
||||
font-size: 10px;
|
||||
font-weight: 760;
|
||||
letter-spacing: 0;
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-actions {
|
||||
flex: 0 0 auto;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-icon-button {
|
||||
display: inline-grid;
|
||||
width: var(--ai-console-control-h);
|
||||
height: var(--ai-console-control-h);
|
||||
flex: 0 0 var(--ai-console-control-h);
|
||||
place-items: center;
|
||||
border: 0;
|
||||
border-radius: 15px;
|
||||
background: var(--nodedc-glass-control-bg);
|
||||
color: rgba(255, 255, 255, 0.82);
|
||||
cursor: pointer;
|
||||
outline: none !important;
|
||||
padding: 0;
|
||||
box-shadow: var(--nodedc-glass-control-shadow) !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-icon-button:hover {
|
||||
background: var(--nodedc-glass-control-hover);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-icon-button[data-active="true"] {
|
||||
background: var(--brand);
|
||||
color: var(--brand-contrast);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-icon-button--sm {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
flex-basis: 38px;
|
||||
border-radius: 13px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-icon-button > span:not(.nodedc-glass-modal__close-mark) {
|
||||
font-size: 19px;
|
||||
font-weight: 560;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-threads,
|
||||
.nodedc-ai-workspace-console .ai-console-main {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-threads {
|
||||
display: grid;
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
gap: 14px;
|
||||
padding: 0 12px 18px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-threads__head {
|
||||
min-height: var(--ai-console-control-h);
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-threads__title {
|
||||
margin-top: 7px;
|
||||
color: rgba(255, 255, 255, 0.94);
|
||||
font-size: 15px;
|
||||
font-weight: 760;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread-list {
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
align-content: start;
|
||||
gap: 8px;
|
||||
overflow: auto;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread-list::-webkit-scrollbar,
|
||||
.nodedc-ai-workspace-console .ai-console-messages::-webkit-scrollbar,
|
||||
.nodedc-ai-workspace-console .ai-console-activity__log::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread {
|
||||
position: relative;
|
||||
display: grid;
|
||||
min-height: 52px;
|
||||
min-width: 0;
|
||||
gap: 6px;
|
||||
border: 0;
|
||||
border-radius: 14px;
|
||||
background: var(--nodedc-glass-control-bg);
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
cursor: pointer;
|
||||
outline: none !important;
|
||||
padding: 10px 13px;
|
||||
text-align: left;
|
||||
box-shadow: var(--nodedc-glass-control-shadow) !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread[data-editing="true"] {
|
||||
padding-right: 38px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread:hover,
|
||||
.nodedc-ai-workspace-console .ai-console-thread[data-active="true"] {
|
||||
background: var(--nodedc-glass-control-hover);
|
||||
color: rgba(255, 255, 255, 0.96);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread[data-active="true"] {
|
||||
background: var(--brand);
|
||||
color: var(--brand-contrast);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__row,
|
||||
.nodedc-ai-workspace-console .ai-console-thread small,
|
||||
.nodedc-ai-workspace-console .ai-console-thread__title {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 760;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__title-input {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
outline: none !important;
|
||||
padding: 0;
|
||||
caret-color: currentColor;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__delete {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 12px;
|
||||
bottom: 0;
|
||||
display: inline-grid;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: auto 0;
|
||||
place-items: center;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
opacity: 0.82;
|
||||
outline: none !important;
|
||||
padding: 0;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__delete::before,
|
||||
.nodedc-ai-workspace-console .ai-console-thread__delete::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 10px;
|
||||
height: 1.5px;
|
||||
border-radius: 999px;
|
||||
background: currentColor;
|
||||
content: "";
|
||||
transform: translate(-50%, -50%) rotate(45deg);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__delete::after {
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread small {
|
||||
color: rgba(255, 255, 255, 0.44);
|
||||
font-size: 11px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread[data-active="true"] small {
|
||||
color: rgba(11, 17, 23, 0.68);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thread__status,
|
||||
.nodedc-ai-workspace-console .ai-console-thinking span,
|
||||
.nodedc-ai-workspace-console .ai-console-process__head i {
|
||||
display: inline-block;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
flex: 0 0 7px;
|
||||
border-radius: 999px;
|
||||
background: currentColor;
|
||||
opacity: 0.9;
|
||||
animation: ai-console-thinking-pulse 1.55s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-resizer {
|
||||
position: relative;
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
width: 10px;
|
||||
min-width: 10px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-resizer::before {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
bottom: 18px;
|
||||
left: 50%;
|
||||
width: 1px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
content: "";
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-resizer:hover::before {
|
||||
width: 3px;
|
||||
background: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-main {
|
||||
display: grid;
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
grid-template-rows: minmax(0, 1fr) auto;
|
||||
gap: 14px;
|
||||
padding: 0 18px 18px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-messages {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
overflow: auto;
|
||||
padding: 4px 2px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-message,
|
||||
.nodedc-ai-workspace-console .ai-console-process {
|
||||
display: grid;
|
||||
width: min(76%, 560px);
|
||||
min-width: 0;
|
||||
gap: 8px;
|
||||
align-self: flex-start;
|
||||
border-radius: 18px;
|
||||
background: var(--nodedc-glass-control-bg);
|
||||
padding: 12px 14px;
|
||||
box-shadow: var(--nodedc-glass-control-shadow);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-message[data-role="user"] {
|
||||
align-self: flex-end;
|
||||
background: rgba(var(--nodedc-card-active-rgb), 0.16);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-message__role,
|
||||
.nodedc-ai-workspace-console .ai-console-process__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
color: rgba(255, 255, 255, 0.46);
|
||||
font-size: 10px;
|
||||
font-weight: 760;
|
||||
line-height: 1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-message__role time {
|
||||
color: rgba(255, 255, 255, 0.34);
|
||||
font: inherit;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-message__text {
|
||||
color: rgba(255, 255, 255, 0.86);
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-rich {
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-rich p {
|
||||
margin: 0;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-process__head {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.075);
|
||||
padding-bottom: 9px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-process__head i {
|
||||
background: var(--brand);
|
||||
color: var(--brand);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-composer {
|
||||
position: relative;
|
||||
min-height: 54px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-composer textarea {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
height: 54px;
|
||||
min-height: 54px;
|
||||
max-height: 128px;
|
||||
resize: none;
|
||||
border: 0 !important;
|
||||
border-radius: 18px;
|
||||
background: var(--nodedc-glass-control-bg);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
font: inherit;
|
||||
font-size: 13px;
|
||||
line-height: 1.2;
|
||||
outline: none !important;
|
||||
padding: 18px 16px;
|
||||
box-shadow: var(--nodedc-glass-control-shadow) !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-composer textarea::placeholder {
|
||||
color: rgba(255, 255, 255, 0.34);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-composer textarea:disabled {
|
||||
color: rgba(255, 255, 255, 0.46);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-send {
|
||||
display: inline-grid;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
flex: 0 0 54px;
|
||||
place-items: center;
|
||||
border: 0;
|
||||
border-radius: 18px;
|
||||
background: var(--brand);
|
||||
color: var(--brand-contrast);
|
||||
cursor: pointer;
|
||||
outline: none !important;
|
||||
padding: 0;
|
||||
box-shadow: var(--nodedc-glass-control-shadow) !important;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-send:disabled {
|
||||
background: var(--nodedc-glass-control-bg);
|
||||
color: rgba(255, 255, 255, 0.32);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thinking {
|
||||
display: inline-grid;
|
||||
width: 22px;
|
||||
height: 54px;
|
||||
flex: 0 0 22px;
|
||||
place-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-thinking span {
|
||||
background: var(--brand);
|
||||
color: var(--brand);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(100% + 16px);
|
||||
isolation: isolate;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
width: 330px;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
gap: 14px;
|
||||
overflow: hidden;
|
||||
border-radius: 22px;
|
||||
background: var(--nodedc-glass-panel-bg);
|
||||
color: rgba(255, 255, 255, 0.92);
|
||||
pointer-events: auto;
|
||||
padding: 18px 16px 16px;
|
||||
box-shadow: var(--nodedc-glass-panel-shadow);
|
||||
-webkit-backdrop-filter: blur(64px) saturate(150%) brightness(1.08);
|
||||
backdrop-filter: blur(64px) saturate(150%) brightness(1.08);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity__header {
|
||||
min-width: 0;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity__header h3 {
|
||||
margin: 6px 0 0;
|
||||
color: rgba(255, 255, 255, 0.94);
|
||||
font-size: 16px;
|
||||
font-weight: 760;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity__actions {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity {
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__head {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__head span {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: rgba(var(--nodedc-card-active-rgb), 0.96);
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
line-height: 1.25;
|
||||
text-overflow: ellipsis;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__head small {
|
||||
color: rgba(255, 255, 255, 0.42);
|
||||
font-size: 10px;
|
||||
font-weight: 760;
|
||||
line-height: 1.25;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__log {
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
align-content: start;
|
||||
gap: 5px;
|
||||
overflow: auto;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__line {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
grid-template-columns: 72px minmax(0, 1fr);
|
||||
align-items: start;
|
||||
gap: 9px;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__line span {
|
||||
overflow: hidden;
|
||||
color: rgba(255, 255, 255, 0.42);
|
||||
font-weight: 760;
|
||||
text-overflow: ellipsis;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-activity__line code {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
||||
text-overflow: ellipsis;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize-layer {
|
||||
position: absolute;
|
||||
inset: -6px;
|
||||
z-index: 4;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize {
|
||||
position: absolute;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--top,
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--bottom {
|
||||
right: 14px;
|
||||
left: 14px;
|
||||
height: 12px;
|
||||
cursor: ns-resize;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--top {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--left,
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--right {
|
||||
top: 14px;
|
||||
bottom: 14px;
|
||||
width: 12px;
|
||||
cursor: ew-resize;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--top-left,
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--top-right,
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--bottom-right,
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--bottom-left {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--top-left {
|
||||
top: 0;
|
||||
left: 0;
|
||||
cursor: nwse-resize;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--top-right {
|
||||
top: 0;
|
||||
right: 0;
|
||||
cursor: nesw-resize;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--bottom-right {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
cursor: nwse-resize;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize--bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
cursor: nesw-resize;
|
||||
}
|
||||
|
||||
@keyframes ai-console-thinking-pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0.72);
|
||||
box-shadow: 0 0 0 0 rgba(var(--nodedc-card-active-rgb), 0.22);
|
||||
opacity: 0.58;
|
||||
}
|
||||
|
||||
48% {
|
||||
transform: scale(1.75);
|
||||
box-shadow: 0 0 0 9px rgba(var(--nodedc-card-active-rgb), 0.04);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1040px) {
|
||||
.nodedc-ai-workspace-console {
|
||||
left: 12px !important;
|
||||
top: 72px !important;
|
||||
width: calc(100vw - 24px) !important;
|
||||
height: calc(100vh - 88px) !important;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-shell {
|
||||
grid-template-columns: minmax(190px, 35vw) 8px minmax(0, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.nodedc-ai-workspace-console .ai-console-shell {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: auto 148px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-topbar {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-threads {
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
padding: 0 12px 10px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-resizer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-main {
|
||||
grid-column: 1;
|
||||
grid-row: 3;
|
||||
padding: 0 12px 12px;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-title-block h2 {
|
||||
max-width: 42vw;
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-side-activity {
|
||||
right: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: min(280px, calc(100vh - 96px));
|
||||
transform: translateY(calc(-100% - 12px));
|
||||
}
|
||||
|
||||
.nodedc-ai-workspace-console .ai-console-window-resize-layer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.nodedc-bottom-dock-aware-padding {
|
||||
padding-bottom: calc(var(--nodedc-quick-add-reserve, 2.5rem) + 0.5rem);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue