mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-14 16:44:07 -08:00
Some more restructuring
This commit is contained in:
parent
32b4eb523b
commit
6f4a8171ce
|
@ -1,11 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { Ref } from 'vue';
|
||||||
import { provide, watch, computed, ref, watchEffect } from 'vue';
|
import { provide, watch, computed, ref, watchEffect } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
|
|
||||||
// Constants & Symbols
|
|
||||||
import { ChatOptionsSymbol, ChatSymbol } from '@n8n/chat/constants';
|
import { ChatOptionsSymbol, ChatSymbol } from '@n8n/chat/constants';
|
||||||
|
import type { Router } from 'vue-router';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { chatEventBus } from '@n8n/chat/event-buses';
|
||||||
import { VIEWS } from '@/constants';
|
import { VIEWS } from '@/constants';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import ChatMessagesPanel from './components/ChatMessagesPanel.vue';
|
import ChatMessagesPanel from './components/ChatMessagesPanel.vue';
|
||||||
|
@ -19,91 +20,67 @@ import { useI18n } from '@/composables/useI18n';
|
||||||
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
import { useNodeHelpers } from '@/composables/useNodeHelpers';
|
||||||
import { useRunWorkflow } from '@/composables/useRunWorkflow';
|
import { useRunWorkflow } from '@/composables/useRunWorkflow';
|
||||||
|
|
||||||
// Event Bus
|
|
||||||
import { chatEventBus } from '@n8n/chat/event-buses';
|
|
||||||
|
|
||||||
// Stores
|
|
||||||
import { useCanvasStore } from '@/stores/canvas.store';
|
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { Chat, ChatMessage, ChatOptions } from '@n8n/chat/types';
|
import type { Chat, ChatMessage, ChatOptions } from '@n8n/chat/types';
|
||||||
import type { RunWorkflowChatPayload } from './composables/useChatMessaging';
|
import type { RunWorkflowChatPayload } from './composables/useChatMessaging';
|
||||||
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
|
import { useCanvasStore } from '@/stores/canvas.store';
|
||||||
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
|
|
||||||
// Initialize stores and composables
|
export interface ChatProps {
|
||||||
const setupStores = () => {
|
// Injected stores for testing
|
||||||
const router = useRouter();
|
workflowsStore?: ReturnType<typeof useWorkflowsStore>;
|
||||||
const uiStore = useUIStore();
|
uiStore?: ReturnType<typeof useUIStore>;
|
||||||
const locale = useI18n();
|
canvasStore?: ReturnType<typeof useCanvasStore>;
|
||||||
const nodeHelpers = useNodeHelpers();
|
nodeTypesStore?: ReturnType<typeof useNodeTypesStore>;
|
||||||
const workflowsStore = useWorkflowsStore();
|
nodeHelpers?: ReturnType<typeof useNodeHelpers>;
|
||||||
const canvasStore = useCanvasStore();
|
initialSessionId?: string;
|
||||||
const nodeTypesStore = useNodeTypesStore();
|
router?: Router;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
// Props for dependency injection (makes testing easier)
|
||||||
router,
|
const props = withDefaults(defineProps<ChatProps>(), {
|
||||||
uiStore,
|
workflowsStore: () => useWorkflowsStore(),
|
||||||
locale,
|
uiStore: () => useUIStore(),
|
||||||
nodeHelpers,
|
canvasStore: () => useCanvasStore(),
|
||||||
workflowsStore,
|
nodeTypesStore: () => useNodeTypesStore(),
|
||||||
canvasStore,
|
nodeHelpers: () => useNodeHelpers(),
|
||||||
nodeTypesStore,
|
router: () => useRouter(),
|
||||||
};
|
initialSessionId: () => uuid().replace(/-/g, ''),
|
||||||
};
|
});
|
||||||
|
|
||||||
// Component state
|
// Component state
|
||||||
const setupState = () => {
|
|
||||||
const messages = ref<ChatMessage[]>([]);
|
const messages = ref<ChatMessage[]>([]);
|
||||||
const currentSessionId = ref<string>(uuid().replace(/-/g, ''));
|
const currentSessionId = ref<string>(props.initialSessionId);
|
||||||
const isDisabled = ref(false);
|
const isDisabled = ref(false);
|
||||||
const container = ref<HTMLElement>();
|
const container = ref<HTMLElement>();
|
||||||
|
|
||||||
return {
|
// Computed properties
|
||||||
|
const workflow = computed(() => props.workflowsStore.getCurrentWorkflow());
|
||||||
|
const isLoading = computed(() => props.uiStore.isActionActive.workflowRunning);
|
||||||
|
const allConnections = computed(() => props.workflowsStore.allConnections);
|
||||||
|
const isChatOpen = computed(() => props.workflowsStore.isChatPanelOpen);
|
||||||
|
const isLogsOpen = computed(() => props.workflowsStore.isLogsPanelOpen);
|
||||||
|
const previousChatMessages = computed(() => props.workflowsStore.getPastChatMessages);
|
||||||
|
|
||||||
|
// Expose internal state for testing
|
||||||
|
defineExpose({
|
||||||
messages,
|
messages,
|
||||||
currentSessionId,
|
currentSessionId,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
container,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize component
|
|
||||||
const { router, uiStore, locale, nodeHelpers, workflowsStore, canvasStore, nodeTypesStore } =
|
|
||||||
setupStores();
|
|
||||||
|
|
||||||
const { messages, currentSessionId, isDisabled, container } = setupState();
|
|
||||||
|
|
||||||
// Computed properties
|
|
||||||
const setupComputed = () => {
|
|
||||||
const workflow = computed(() => workflowsStore.getCurrentWorkflow());
|
|
||||||
const isLoading = computed(() => uiStore.isActionActive.workflowRunning);
|
|
||||||
const allConnections = computed(() => workflowsStore.allConnections);
|
|
||||||
const isChatOpen = computed(() => workflowsStore.isChatPanelOpen);
|
|
||||||
const isLogsOpen = computed(() => workflowsStore.isLogsPanelOpen);
|
|
||||||
const previousChatMessages = computed(() => workflowsStore.getPastChatMessages);
|
|
||||||
|
|
||||||
return {
|
|
||||||
workflow,
|
workflow,
|
||||||
isLoading,
|
isLoading,
|
||||||
allConnections,
|
});
|
||||||
isChatOpen,
|
|
||||||
isLogsOpen,
|
|
||||||
previousChatMessages,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const { workflow, isLoading, allConnections, isChatOpen, isLogsOpen, previousChatMessages } =
|
const { runWorkflow } = useRunWorkflow({ router: props.router });
|
||||||
setupComputed();
|
|
||||||
|
|
||||||
// Initialize features
|
|
||||||
const { runWorkflow } = useRunWorkflow({ router });
|
|
||||||
|
|
||||||
|
// Initialize features with injected dependencies
|
||||||
const { chatTriggerNode, connectedNode, allowFileUploads, setChatTriggerNode, setConnectedNode } =
|
const { chatTriggerNode, connectedNode, allowFileUploads, setChatTriggerNode, setConnectedNode } =
|
||||||
useChatTrigger({
|
useChatTrigger({
|
||||||
workflow,
|
workflow,
|
||||||
getNodeByName: workflowsStore.getNodeByName,
|
getNodeByName: props.workflowsStore.getNodeByName,
|
||||||
getNodeType: nodeTypesStore.getNodeType,
|
getNodeType: props.nodeTypesStore.getNodeType,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { sendMessage, getChatMessages } = useChatMessaging({
|
const { sendMessage, getChatMessages } = useChatMessaging({
|
||||||
|
@ -113,8 +90,8 @@ const { sendMessage, getChatMessages } = useChatMessaging({
|
||||||
sessionId: currentSessionId,
|
sessionId: currentSessionId,
|
||||||
workflow,
|
workflow,
|
||||||
isLoading,
|
isLoading,
|
||||||
executionResultData: computed(() => workflowsStore.getWorkflowExecution?.data?.resultData),
|
executionResultData: computed(() => props.workflowsStore.getWorkflowExecution?.data?.resultData),
|
||||||
getWorkflowResultDataByNodeName: workflowsStore.getWorkflowResultDataByNodeName,
|
getWorkflowResultDataByNodeName: props.workflowsStore.getWorkflowResultDataByNodeName,
|
||||||
onRunChatWorkflow,
|
onRunChatWorkflow,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -128,14 +105,22 @@ const {
|
||||||
onWindowResize,
|
onWindowResize,
|
||||||
} = useResize(container);
|
} = useResize(container);
|
||||||
|
|
||||||
// Chat configuration
|
// Extracted pure functions for better testability
|
||||||
const setupChatConfig = (): { chatConfig: Chat; chatOptions: ChatOptions } => {
|
function createChatConfig(params: {
|
||||||
|
messages: Chat['messages'];
|
||||||
|
sendMessage: Chat['sendMessage'];
|
||||||
|
currentSessionId: Chat['currentSessionId'];
|
||||||
|
isLoading: Ref<boolean>;
|
||||||
|
isDisabled: Ref<boolean>;
|
||||||
|
allowFileUploads: Ref<boolean>;
|
||||||
|
locale: ReturnType<typeof useI18n>;
|
||||||
|
}): { chatConfig: Chat; chatOptions: ChatOptions } {
|
||||||
const chatConfig: Chat = {
|
const chatConfig: Chat = {
|
||||||
messages,
|
messages: params.messages,
|
||||||
sendMessage,
|
sendMessage: params.sendMessage,
|
||||||
initialMessages: ref([]),
|
initialMessages: ref([]),
|
||||||
currentSessionId,
|
currentSessionId: params.currentSessionId,
|
||||||
waitingForResponse: isLoading,
|
waitingForResponse: params.isLoading,
|
||||||
};
|
};
|
||||||
|
|
||||||
const chatOptions: ChatOptions = {
|
const chatOptions: ChatOptions = {
|
||||||
|
@ -144,7 +129,7 @@ const setupChatConfig = (): { chatConfig: Chat; chatOptions: ChatOptions } => {
|
||||||
title: '',
|
title: '',
|
||||||
footer: '',
|
footer: '',
|
||||||
subtitle: '',
|
subtitle: '',
|
||||||
inputPlaceholder: locale.baseText('chat.window.chat.placeholder'),
|
inputPlaceholder: params.locale.baseText('chat.window.chat.placeholder'),
|
||||||
getStarted: '',
|
getStarted: '',
|
||||||
closeButtonTooltip: '',
|
closeButtonTooltip: '',
|
||||||
},
|
},
|
||||||
|
@ -152,34 +137,47 @@ const setupChatConfig = (): { chatConfig: Chat; chatOptions: ChatOptions } => {
|
||||||
webhookUrl: '',
|
webhookUrl: '',
|
||||||
mode: 'window',
|
mode: 'window',
|
||||||
showWindowCloseButton: true,
|
showWindowCloseButton: true,
|
||||||
disabled: isDisabled,
|
disabled: params.isDisabled,
|
||||||
allowFileUploads,
|
allowFileUploads: params.allowFileUploads,
|
||||||
allowedFilesMimeTypes: '',
|
allowedFilesMimeTypes: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
return { chatConfig, chatOptions };
|
return { chatConfig, chatOptions };
|
||||||
};
|
}
|
||||||
|
|
||||||
const { chatConfig, chatOptions } = setupChatConfig();
|
function displayExecution(params: { router: Router; workflowId: string; executionId: string }) {
|
||||||
|
const route = params.router.resolve({
|
||||||
// Methods
|
|
||||||
const displayExecution = (executionId: string) => {
|
|
||||||
const route = router.resolve({
|
|
||||||
name: VIEWS.EXECUTION_PREVIEW,
|
name: VIEWS.EXECUTION_PREVIEW,
|
||||||
params: { name: workflow.value.id, executionId },
|
params: { name: params.workflowId, executionId: params.executionId },
|
||||||
});
|
});
|
||||||
window.open(route.href, '_blank');
|
window.open(route.href, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshSession(params: { messages: Ref<ChatMessage[]>; currentSessionId: Ref<string> }) {
|
||||||
|
props.workflowsStore.setWorkflowExecutionData(null);
|
||||||
|
props.nodeHelpers.updateNodesExecutionIssues();
|
||||||
|
params.messages.value = [];
|
||||||
|
params.currentSessionId.value = uuid().replace(/-/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event handlers
|
||||||
|
const handleDisplayExecution = (executionId: string) => {
|
||||||
|
displayExecution({
|
||||||
|
router: props.router,
|
||||||
|
workflowId: workflow.value.id,
|
||||||
|
executionId,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshSession = () => {
|
const handleRefreshSession = () => {
|
||||||
workflowsStore.setWorkflowExecutionData(null);
|
refreshSession({
|
||||||
nodeHelpers.updateNodesExecutionIssues();
|
messages,
|
||||||
messages.value = [];
|
currentSessionId,
|
||||||
currentSessionId.value = uuid().replace(/-/g, '');
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeLogs = () => {
|
const closeLogs = () => {
|
||||||
workflowsStore.setPanelOpen('logs', false);
|
props.workflowsStore.setPanelOpen('logs', false);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function onRunChatWorkflow(payload: RunWorkflowChatPayload) {
|
async function onRunChatWorkflow(payload: RunWorkflowChatPayload) {
|
||||||
|
@ -189,10 +187,21 @@ async function onRunChatWorkflow(payload: RunWorkflowChatPayload) {
|
||||||
source: payload.source,
|
source: payload.source,
|
||||||
});
|
});
|
||||||
|
|
||||||
workflowsStore.appendChatMessage(payload.message);
|
props.workflowsStore.appendChatMessage(payload.message);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize chat config
|
||||||
|
const { chatConfig, chatOptions } = createChatConfig({
|
||||||
|
messages,
|
||||||
|
sendMessage,
|
||||||
|
currentSessionId,
|
||||||
|
isLoading,
|
||||||
|
isDisabled,
|
||||||
|
allowFileUploads,
|
||||||
|
locale: useI18n(),
|
||||||
|
});
|
||||||
|
|
||||||
// Provide chat context
|
// Provide chat context
|
||||||
provide(ChatSymbol, chatConfig);
|
provide(ChatSymbol, chatConfig);
|
||||||
provide(ChatOptionsSymbol, chatOptions);
|
provide(ChatOptionsSymbol, chatOptions);
|
||||||
|
@ -220,7 +229,7 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
() => allConnections.value,
|
() => allConnections.value,
|
||||||
() => {
|
() => {
|
||||||
if (canvasStore.isLoading) return;
|
if (props.canvasStore.isLoading) return;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!chatTriggerNode.value) {
|
if (!chatTriggerNode.value) {
|
||||||
setChatTriggerNode();
|
setChatTriggerNode();
|
||||||
|
@ -232,7 +241,7 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
canvasStore.setPanelHeight(isChatOpen.value || isLogsOpen.value ? height.value : 0);
|
props.canvasStore.setPanelHeight(isChatOpen.value || isLogsOpen.value ? height.value : 0);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -261,8 +270,8 @@ watchEffect(() => {
|
||||||
:messages="messages"
|
:messages="messages"
|
||||||
:session-id="currentSessionId"
|
:session-id="currentSessionId"
|
||||||
:past-chat-messages="previousChatMessages"
|
:past-chat-messages="previousChatMessages"
|
||||||
@refresh-session="refreshSession"
|
@refresh-session="handleRefreshSession"
|
||||||
@display-execution="displayExecution"
|
@display-execution="handleDisplayExecution"
|
||||||
@send-message="sendMessage"
|
@send-message="sendMessage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue