) => {
inputRef?.focus();
}}
autoFocus
+ autoComplete="off"
value={jobName}
onChange={e => {
setJobName(e.target.value);
diff --git a/assets/test/collaborative-editor/components/form/number-field.test.tsx b/assets/test/collaborative-editor/components/form/number-field.test.tsx
index 9beef6914b3..32a31b97d21 100644
--- a/assets/test/collaborative-editor/components/form/number-field.test.tsx
+++ b/assets/test/collaborative-editor/components/form/number-field.test.tsx
@@ -48,11 +48,13 @@ describe('NumberField', () => {
);
}
- it('renders with label and help text', () => {
+ it('renders with label, help text, and autoComplete="off"', () => {
render();
- expect(screen.getByLabelText('Count')).toBeInTheDocument();
+ const input = screen.getByLabelText('Count') as HTMLInputElement;
+ expect(input).toBeInTheDocument();
expect(screen.getByText('Enter a number')).toBeInTheDocument();
+ expect(input).toHaveAttribute('autocomplete', 'off');
});
it('shows placeholder when value is null', () => {
diff --git a/assets/test/collaborative-editor/components/form/text-field.test.tsx b/assets/test/collaborative-editor/components/form/text-field.test.tsx
new file mode 100644
index 00000000000..3aa08b037e1
--- /dev/null
+++ b/assets/test/collaborative-editor/components/form/text-field.test.tsx
@@ -0,0 +1,58 @@
+import { render, screen } from '@testing-library/react';
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { useAppForm } from '../../../../js/collaborative-editor/components/form';
+import * as useWorkflowModule from '../../../../js/collaborative-editor/hooks/useWorkflow';
+
+// Mock useWorkflowState and useWorkflowActions (required by useAppForm's
+// useValidation hook, which reads from the collaborative workflow store)
+vi.mock('../../../../js/collaborative-editor/hooks/useWorkflow', () => ({
+ useWorkflowState: vi.fn(),
+ useWorkflowActions: vi.fn(() => ({
+ setClientErrors: vi.fn(),
+ })),
+}));
+
+describe('TextField', () => {
+ beforeEach(() => {
+ vi.clearAllMocks();
+ vi.mocked(useWorkflowModule.useWorkflowState).mockImplementation(
+ (selector?: (state: any) => any) => {
+ const state = {
+ workflow: { id: 'w-1', errors: {} },
+ jobs: [],
+ triggers: [],
+ edges: [],
+ };
+ return selector ? selector(state) : state;
+ }
+ );
+ });
+
+ function TestForm({ defaultValue = '' }: { defaultValue?: string }) {
+ const form = useAppForm({
+ defaultValues: { name: defaultValue },
+ });
+
+ return (
+
+ {field => }
+
+ );
+ }
+
+ it('renders with label, placeholder, and autoComplete="off"', () => {
+ render();
+
+ const input = screen.getByLabelText('Name') as HTMLInputElement;
+ expect(input).toBeInTheDocument();
+ expect(input.placeholder).toBe('Enter a name');
+ expect(input).toHaveAttribute('autocomplete', 'off');
+ });
+
+ it('displays initial value', () => {
+ render();
+
+ const input = screen.getByLabelText('Name') as HTMLInputElement;
+ expect(input.value).toBe('hello');
+ });
+});
diff --git a/lib/lightning_web/components/new_inputs.ex b/lib/lightning_web/components/new_inputs.ex
index f54fc8b0c3d..c00d671b562 100644
--- a/lib/lightning_web/components/new_inputs.ex
+++ b/lib/lightning_web/components/new_inputs.ex
@@ -400,9 +400,11 @@ defmodule LightningWeb.Components.NewInputs do
attr :placeholder, :string, default: ""
+ attr :autocomplete, :string, default: "off"
+
attr :rest, :global,
include:
- ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
+ ~w(accept capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step)
attr :class, :string, default: ""
@@ -635,6 +637,7 @@ defmodule LightningWeb.Components.NewInputs do
id={@id}
name={@name}
class={["rounded-md w-full font-mono bg-slate-800 text-slate-100", @class]}
+ autocomplete={@autocomplete}
value={@value}
placeholder={@placeholder}
errors={@errors}
@@ -660,6 +663,7 @@ defmodule LightningWeb.Components.NewInputs do
- <.input field={f[:last_name]} required={true} label="Last Name" />
+ <.input
+ field={f[:last_name]}
+ required={true}
+ label="Last Name"
+ autocomplete="family-name"
+ />
<.input
@@ -43,6 +49,7 @@
type="email"
label="Email"
required={true}
+ autocomplete="email"
/>
@@ -51,6 +58,7 @@
type="password"
label="Password"
required={true}
+ autocomplete="new-password"
/>
diff --git a/lib/lightning_web/controllers/user_reset_password_html/edit.html.heex b/lib/lightning_web/controllers/user_reset_password_html/edit.html.heex
index 9a766d1d33b..a9a92e5538e 100644
--- a/lib/lightning_web/controllers/user_reset_password_html/edit.html.heex
+++ b/lib/lightning_web/controllers/user_reset_password_html/edit.html.heex
@@ -27,7 +27,12 @@
<.label for={:password}>New password
- <.input type="password" field={f[:password]} required />
+ <.input
+ type="password"
+ field={f[:password]}
+ required
+ autocomplete="new-password"
+ />
@@ -38,6 +43,7 @@
type="password"
field={f[:password_confirmation]}
required
+ autocomplete="new-password"
/>
diff --git a/lib/lightning_web/controllers/user_session_html/new.html.heex b/lib/lightning_web/controllers/user_session_html/new.html.heex
index 8a945fc56f7..8e2949b9f8c 100644
--- a/lib/lightning_web/controllers/user_session_html/new.html.heex
+++ b/lib/lightning_web/controllers/user_session_html/new.html.heex
@@ -33,10 +33,16 @@
field={f[:email]}
required={true}
label="Email"
+ autocomplete="email"
/>
- <.input type="password" field={f[:password]} label="Password" />
+ <.input
+ type="password"
+ field={f[:password]}
+ label="Password"
+ autocomplete="current-password"
+ />
<.check_box form={f} field={:remember_me}>
diff --git a/lib/lightning_web/controllers/user_totp_html/new.html.heex b/lib/lightning_web/controllers/user_totp_html/new.html.heex
index 5821ff3f5fe..a852e526b23 100644
--- a/lib/lightning_web/controllers/user_totp_html/new.html.heex
+++ b/lib/lightning_web/controllers/user_totp_html/new.html.heex
@@ -30,7 +30,7 @@
type="text"
field={f[:code]}
required="true"
- autocomplete="off"
+ autocomplete="one-time-code"
inputmode="numeric"
placeholder="XXXXXX"
class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
diff --git a/lib/lightning_web/live/book_demo_banner.ex b/lib/lightning_web/live/book_demo_banner.ex
index 6440ad46efa..2448ad34c58 100644
--- a/lib/lightning_web/live/book_demo_banner.ex
+++ b/lib/lightning_web/live/book_demo_banner.ex
@@ -157,8 +157,20 @@ defmodule LightningWeb.BookDemoBanner do
phx-submit="schedule-call"
>
- <.input type="text" field={f[:name]} label="Name" required={true} />
- <.input type="text" field={f[:email]} label="Email" required={true} />
+ <.input
+ type="text"
+ field={f[:name]}
+ label="Name"
+ required={true}
+ autocomplete="name"
+ />
+ <.input
+ type="text"
+ field={f[:email]}
+ label="Email"
+ required={true}
+ autocomplete="email"
+ />
<.input
type="textarea"
field={f[:message]}
diff --git a/lib/lightning_web/live/components/form.ex b/lib/lightning_web/live/components/form.ex
index 2e5d519616a..0352440524e 100644
--- a/lib/lightning_web/live/components/form.ex
+++ b/lib/lightning_web/live/components/form.ex
@@ -128,7 +128,10 @@ defmodule LightningWeb.Components.Form do
label_classes: label_classes,
error_classes: error_classes,
input_classes: input_classes,
- opts: assigns.rest |> assigns_to_attributes()
+ opts:
+ assigns.rest
+ |> assigns_to_attributes()
+ |> Keyword.put_new(:autocomplete, "off")
)
|> assign_new(:label, fn -> nil end)
|> assign_new(:hint, fn -> nil end)
@@ -269,7 +272,10 @@ defmodule LightningWeb.Components.Form do
label_classes: label_classes,
error_classes: error_classes,
input_classes: input_classes,
- opts: assigns.rest |> assigns_to_attributes()
+ opts:
+ assigns.rest
+ |> assigns_to_attributes()
+ |> Keyword.put_new(:autocomplete, "off")
)
~H"""
diff --git a/lib/lightning_web/live/credential_live/json_schema_body_component.ex b/lib/lightning_web/live/credential_live/json_schema_body_component.ex
index 1689873580d..1b0246e9ed3 100644
--- a/lib/lightning_web/live/credential_live/json_schema_body_component.ex
+++ b/lib/lightning_web/live/credential_live/json_schema_body_component.ex
@@ -78,6 +78,7 @@ defmodule LightningWeb.CredentialLive.JsonSchemaBodyComponent do
field={@form_field}
label={@title}
required={@required}
+ autocomplete={if @type == "password", do: "new-password"}
checked={@type == "checkbox" and @form_field.value == true}
/>
diff --git a/lib/lightning_web/live/credential_live/oauth_client_form_component.ex b/lib/lightning_web/live/credential_live/oauth_client_form_component.ex
index bc948abc4d1..5540231e9f3 100644
--- a/lib/lightning_web/live/credential_live/oauth_client_form_component.ex
+++ b/lib/lightning_web/live/credential_live/oauth_client_form_component.ex
@@ -433,6 +433,7 @@ defmodule LightningWeb.CredentialLive.OauthClientFormComponent do
field={f[:client_secret]}
label="Client Secret"
required="true"
+ autocomplete="new-password"
/>
diff --git a/lib/lightning_web/live/first_setup_live/superuser.html.heex b/lib/lightning_web/live/first_setup_live/superuser.html.heex
index 09799be5ed2..ae37d082e8d 100644
--- a/lib/lightning_web/live/first_setup_live/superuser.html.heex
+++ b/lib/lightning_web/live/first_setup_live/superuser.html.heex
@@ -35,7 +35,12 @@
- <.input type="password" field={f[:password]} label="Password" />
+ <.input
+ type="password"
+ field={f[:password]}
+ label="Password"
+ autocomplete="new-password"
+ />
@@ -45,6 +50,7 @@
type="password"
field={f[:password_confirmation]}
label="Password confirmation"
+ autocomplete="new-password"
/>
diff --git a/lib/lightning_web/live/job_live/kafka_setup_component.ex b/lib/lightning_web/live/job_live/kafka_setup_component.ex
index ef49daf7db4..cb2c065210d 100644
--- a/lib/lightning_web/live/job_live/kafka_setup_component.ex
+++ b/lib/lightning_web/live/job_live/kafka_setup_component.ex
@@ -69,7 +69,6 @@ defmodule LightningWeb.JobLive.KafkaSetupComponent do
type="text"
field={kafka_config[:username]}
label="Username"
- autocomplete="off"
disabled={@disabled}
/>
@@ -81,6 +80,7 @@ defmodule LightningWeb.JobLive.KafkaSetupComponent do
label="Password"
disabled={@disabled}
value={password}
+ autocomplete="new-password"
/>
diff --git a/lib/lightning_web/live/profile_live/form_component.html.heex b/lib/lightning_web/live/profile_live/form_component.html.heex
index 7e82d8bf32e..5ada64c6dca 100644
--- a/lib/lightning_web/live/profile_live/form_component.html.heex
+++ b/lib/lightning_web/live/profile_live/form_component.html.heex
@@ -17,6 +17,7 @@
field={f[:first_name]}
label="First name"
required="true"
+ autocomplete="given-name"
/>
@@ -25,6 +26,7 @@
field={f[:last_name]}
label="Last name"
required="true"
+ autocomplete="family-name"
/>
@@ -80,6 +82,7 @@
label="Enter password to confirm"
required="true"
phx-debounce="blur"
+ autocomplete="current-password"
/>
@@ -113,6 +116,7 @@
field={f[:password]}
label="New password"
required="true"
+ autocomplete="new-password"
/>
@@ -121,6 +125,7 @@
field={f[:password_confirmation]}
label="Confirm new password"
required="true"
+ autocomplete="new-password"
/>
@@ -129,6 +134,7 @@
field={f[:current_password]}
label="Current password"
required="true"
+ autocomplete="current-password"
/>
diff --git a/lib/lightning_web/live/profile_live/mfa_component.html.heex b/lib/lightning_web/live/profile_live/mfa_component.html.heex
index 82eaf208823..209b8a60add 100644
--- a/lib/lightning_web/live/profile_live/mfa_component.html.heex
+++ b/lib/lightning_web/live/profile_live/mfa_component.html.heex
@@ -160,7 +160,7 @@
<.input
type="text"
field={f[:code]}
- autocomplete="off"
+ autocomplete="one-time-code"
placeholder="XXXXXX"
label="Verify the code from the app"
/>
diff --git a/lib/lightning_web/live/re_authenticate_live/new.html.heex b/lib/lightning_web/live/re_authenticate_live/new.html.heex
index 2d5f8fce1e4..0f0c02c52de 100644
--- a/lib/lightning_web/live/re_authenticate_live/new.html.heex
+++ b/lib/lightning_web/live/re_authenticate_live/new.html.heex
@@ -61,6 +61,7 @@
type="password"
field={f[:password]}
required="true"
+ autocomplete="current-password"
class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
/>
<% else %>
@@ -68,7 +69,7 @@
type="text"
field={f[:code]}
required="true"
- autocomplete="off"
+ autocomplete="one-time-code"
inputmode="numeric"
placeholder="XXXXXX"
class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
diff --git a/lib/lightning_web/live/sandbox_live/components.ex b/lib/lightning_web/live/sandbox_live/components.ex
index f6e20e2fe61..f2b2728b878 100644
--- a/lib/lightning_web/live/sandbox_live/components.ex
+++ b/lib/lightning_web/live/sandbox_live/components.ex
@@ -167,7 +167,6 @@ defmodule LightningWeb.SandboxLive.Components do
field={@confirm_form[:name]}
label="Sandbox name"
placeholder={@sandbox.name}
- autocomplete="off"
required
/>
<.errors field={@confirm_form[:name]} />
diff --git a/lib/lightning_web/live/sandbox_live/form_component.ex b/lib/lightning_web/live/sandbox_live/form_component.ex
index ce40b72407e..c8a590c8962 100644
--- a/lib/lightning_web/live/sandbox_live/form_component.ex
+++ b/lib/lightning_web/live/sandbox_live/form_component.ex
@@ -241,7 +241,6 @@ defmodule LightningWeb.SandboxLive.FormComponent do
field={f[:raw_name]}
label="Name"
required
- autocomplete="off"
placeholder="My Sandbox"
phx-debounce="300"
/>
diff --git a/lib/lightning_web/live/tokens_live/index.html.heex b/lib/lightning_web/live/tokens_live/index.html.heex
index 0d3d20c0ef5..b0c0e135b57 100644
--- a/lib/lightning_web/live/tokens_live/index.html.heex
+++ b/lib/lightning_web/live/tokens_live/index.html.heex
@@ -43,6 +43,7 @@
value={@new_token}
class="my-auto w-full border-0 bg-inherit disabled:opacity-70 mr-1"
disabled
+ autocomplete="off"
/>