mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(editor): Make AI transform node read only in executions view (#12970)
This commit is contained in:
parent
1a915239c6
commit
ce1deb8aea
|
@ -2,7 +2,7 @@
|
||||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||||
import { mount } from '@vue/test-utils';
|
import { mount } from '@vue/test-utils';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
import ButtonParameter from '@/components/ButtonParameter/ButtonParameter.vue';
|
import ButtonParameter, { type Props } from '@/components/ButtonParameter/ButtonParameter.vue';
|
||||||
import { useNDVStore } from '@/stores/ndv.store';
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { usePostHog } from '@/stores/posthog.store';
|
import { usePostHog } from '@/stores/posthog.store';
|
||||||
|
@ -20,7 +20,7 @@ vi.mock('@/composables/useI18n');
|
||||||
vi.mock('@/composables/useToast');
|
vi.mock('@/composables/useToast');
|
||||||
|
|
||||||
describe('ButtonParameter', () => {
|
describe('ButtonParameter', () => {
|
||||||
const defaultProps = {
|
const defaultProps: Props = {
|
||||||
parameter: {
|
parameter: {
|
||||||
name: 'testParam',
|
name: 'testParam',
|
||||||
displayName: 'Test Parameter',
|
displayName: 'Test Parameter',
|
||||||
|
@ -38,6 +38,7 @@ describe('ButtonParameter', () => {
|
||||||
},
|
},
|
||||||
} as INodeProperties,
|
} as INodeProperties,
|
||||||
value: '',
|
value: '',
|
||||||
|
isReadOnly: false,
|
||||||
path: 'testPath',
|
path: 'testPath',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,9 +79,9 @@ describe('ButtonParameter', () => {
|
||||||
} as any);
|
} as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
const mountComponent = (props = defaultProps) => {
|
const mountComponent = (props: Partial<Props> = {}) => {
|
||||||
return mount(ButtonParameter, {
|
return mount(ButtonParameter, {
|
||||||
props,
|
props: { ...defaultProps, ...props },
|
||||||
global: {
|
global: {
|
||||||
plugins: [createTestingPinia()],
|
plugins: [createTestingPinia()],
|
||||||
},
|
},
|
||||||
|
@ -134,4 +135,10 @@ describe('ButtonParameter', () => {
|
||||||
|
|
||||||
expect(useToast().showMessage).toHaveBeenCalled();
|
expect(useToast().showMessage).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('disables input and button when in read only mode', async () => {
|
||||||
|
const wrapper = mountComponent({ isReadOnly: true });
|
||||||
|
expect(wrapper.find('textarea').attributes('disabled')).toBeDefined();
|
||||||
|
expect(wrapper.find('button').attributes('disabled')).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,7 +14,6 @@ import {
|
||||||
getTextareaCursorPosition,
|
getTextareaCursorPosition,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useUIStore } from '@/stores/ui.store';
|
|
||||||
|
|
||||||
import { propertyNameFromExpression } from '../../utils/mappingUtils';
|
import { propertyNameFromExpression } from '../../utils/mappingUtils';
|
||||||
|
|
||||||
|
@ -24,11 +23,13 @@ const emit = defineEmits<{
|
||||||
valueChanged: [value: IUpdateInformation];
|
valueChanged: [value: IUpdateInformation];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const props = defineProps<{
|
export type Props = {
|
||||||
parameter: INodeProperties;
|
parameter: INodeProperties;
|
||||||
value: string;
|
value: string;
|
||||||
path: string;
|
path: string;
|
||||||
}>();
|
isReadOnly?: boolean;
|
||||||
|
};
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
const { activeNode } = useNDVStore();
|
const { activeNode } = useNDVStore();
|
||||||
|
|
||||||
|
@ -48,8 +49,7 @@ const buttonLabel = computed(
|
||||||
() => props.parameter.typeOptions?.buttonConfig?.label ?? props.parameter.displayName,
|
() => props.parameter.typeOptions?.buttonConfig?.label ?? props.parameter.displayName,
|
||||||
);
|
);
|
||||||
const isSubmitEnabled = computed(() => {
|
const isSubmitEnabled = computed(() => {
|
||||||
if (!hasExecutionData.value) return false;
|
if (!hasExecutionData.value || !prompt.value || props.isReadOnly) return false;
|
||||||
if (!prompt.value) return false;
|
|
||||||
|
|
||||||
const maxlength = inputFieldMaxLength.value;
|
const maxlength = inputFieldMaxLength.value;
|
||||||
if (maxlength && prompt.value.length > maxlength) return false;
|
if (maxlength && prompt.value.length > maxlength) return false;
|
||||||
|
@ -156,16 +156,6 @@ function onPromptInput(inputValue: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function useDarkBackdrop(): string {
|
|
||||||
const theme = useUIStore().appliedTheme;
|
|
||||||
|
|
||||||
if (theme === 'light') {
|
|
||||||
return 'background-color: var(--color-background-xlight);';
|
|
||||||
} else {
|
|
||||||
return 'background-color: var(--color-background-light);';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
parentNodes.value = getParentNodes();
|
parentNodes.value = getParentNodes();
|
||||||
});
|
});
|
||||||
|
@ -213,8 +203,11 @@ async function updateCursorPositionOnMouseMove(event: MouseEvent, activeDrop: bo
|
||||||
color="text-dark"
|
color="text-dark"
|
||||||
>
|
>
|
||||||
</n8n-input-label>
|
</n8n-input-label>
|
||||||
<div :class="$style.inputContainer" :hidden="!hasInputField">
|
<div
|
||||||
<div :class="$style.meta" :style="useDarkBackdrop()">
|
:class="[$style.inputContainer, { [$style.disabled]: isReadOnly }]"
|
||||||
|
:hidden="!hasInputField"
|
||||||
|
>
|
||||||
|
<div :class="$style.meta">
|
||||||
<span
|
<span
|
||||||
v-if="inputFieldMaxLength"
|
v-if="inputFieldMaxLength"
|
||||||
v-show="prompt.length > 1"
|
v-show="prompt.length > 1"
|
||||||
|
@ -240,6 +233,7 @@ async function updateCursorPositionOnMouseMove(event: MouseEvent, activeDrop: bo
|
||||||
:rows="6"
|
:rows="6"
|
||||||
:maxlength="inputFieldMaxLength"
|
:maxlength="inputFieldMaxLength"
|
||||||
:placeholder="parameter.placeholder"
|
:placeholder="parameter.placeholder"
|
||||||
|
:disabled="isReadOnly"
|
||||||
@input="onPromptInput"
|
@input="onPromptInput"
|
||||||
@mousemove="updateCursorPositionOnMouseMove($event, activeDrop)"
|
@mousemove="updateCursorPositionOnMouseMove($event, activeDrop)"
|
||||||
@mouseleave="cleanTextareaRowsData"
|
@mouseleave="cleanTextareaRowsData"
|
||||||
|
@ -279,12 +273,19 @@ async function updateCursorPositionOnMouseMove(event: MouseEvent, activeDrop: bo
|
||||||
.input * {
|
.input * {
|
||||||
border: 1.5px transparent !important;
|
border: 1.5px transparent !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border-radius: var(--border-radius-base);
|
||||||
|
}
|
||||||
|
|
||||||
.input textarea {
|
.input textarea {
|
||||||
font-size: var(--font-size-2xs);
|
font-size: var(--font-size-2xs);
|
||||||
padding-bottom: var(--spacing-2xl);
|
padding-bottom: var(--spacing-2xl);
|
||||||
font-family: var(--font-family);
|
font-family: var(--font-family);
|
||||||
resize: none;
|
resize: none;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.intro {
|
.intro {
|
||||||
font-weight: var(--font-weight-bold);
|
font-weight: var(--font-weight-bold);
|
||||||
font-size: var(--font-size-2xs);
|
font-size: var(--font-size-2xs);
|
||||||
|
@ -300,14 +301,13 @@ async function updateCursorPositionOnMouseMove(event: MouseEvent, activeDrop: bo
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding-bottom: var(--spacing-2xs);
|
padding-bottom: var(--spacing-2xs);
|
||||||
padding-top: var(--spacing-2xs);
|
padding-top: var(--spacing-2xs);
|
||||||
margin: 1px;
|
bottom: 2px;
|
||||||
margin-right: var(--spacing-s);
|
|
||||||
bottom: 0;
|
|
||||||
left: var(--spacing-xs);
|
left: var(--spacing-xs);
|
||||||
right: var(--spacing-xs);
|
right: var(--spacing-xs);
|
||||||
gap: 10px;
|
gap: var(--spacing-2xs);
|
||||||
align-items: end;
|
align-items: end;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
background-color: var(--color-foreground-xlight);
|
||||||
|
|
||||||
* {
|
* {
|
||||||
font-size: var(--font-size-2xs);
|
font-size: var(--font-size-2xs);
|
||||||
|
@ -334,4 +334,9 @@ async function updateCursorPositionOnMouseMove(event: MouseEvent, activeDrop: bo
|
||||||
border: 1.5px solid var(--color-success) !important;
|
border: 1.5px solid var(--color-success) !important;
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
.disabled {
|
||||||
|
.meta {
|
||||||
|
background-color: var(--fill-disabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue