diff --git a/src/lib/components/customId.svelte b/src/lib/components/customId.svelte
index dafdb06613..a1f86ead2e 100644
--- a/src/lib/components/customId.svelte
+++ b/src/lib/components/customId.svelte
@@ -2,13 +2,12 @@
import { trackEvent } from '$lib/actions/analytics';
import { InnerModal } from '$lib/components';
import { InputId } from '$lib/elements/forms';
-
+ import { InputProjectId } from '$lib/elements/forms';
export let show = false;
export let name: string;
export let id: string;
export let autofocus = true;
export let fullWidth = false;
-
$: if (!show) {
id = null;
}
@@ -29,7 +28,11 @@
-
+ {#if name === 'Project'}
+
+ {:else}
+
+ {/if}
diff --git a/src/lib/elements/forms/index.ts b/src/lib/elements/forms/index.ts
index 5e2bbd5181..56cefd5364 100644
--- a/src/lib/elements/forms/index.ts
+++ b/src/lib/elements/forms/index.ts
@@ -23,6 +23,7 @@ export { default as InputPhone } from './inputPhone.svelte';
export { default as InputCron } from './inputCron.svelte';
export { default as InputURL } from './inputURL.svelte';
export { default as InputId } from './inputId.svelte';
+export { default as InputProjectId } from './inputProjectId.svelte';
export { default as InputSecret } from './inputSecret.svelte';
export { default as Helper } from './helper.svelte';
export { default as Label } from './label.svelte';
diff --git a/src/lib/elements/forms/inputProjectId.svelte b/src/lib/elements/forms/inputProjectId.svelte
new file mode 100644
index 0000000000..3c011f4013
--- /dev/null
+++ b/src/lib/elements/forms/inputProjectId.svelte
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+ Allowed characters: lowercase alphanumeric character and non-leading hyphen
+
+
diff --git a/tests/unit/elements/inputProjectId.test.ts b/tests/unit/elements/inputProjectId.test.ts
new file mode 100644
index 0000000000..b2cfcacf71
--- /dev/null
+++ b/tests/unit/elements/inputProjectId.test.ts
@@ -0,0 +1,40 @@
+import '@testing-library/jest-dom';
+import { render } from '@testing-library/svelte';
+import userEvent from '@testing-library/user-event';
+import { InputProjectId } from '../../../src/lib/elements/forms';
+
+const validStrings = ['validstring', 'valid-string', 'validstring123', 'valid-'];
+
+const invalidStrings = ['-invalid', 'Valid', '_invalid', 'Valid123', 'valid.string'];
+
+test('shows id input', () => {
+ const { getByPlaceholderText } = render(InputProjectId);
+ const input = getByPlaceholderText('Enter ID');
+
+ expect(input).toBeInTheDocument();
+ expect(input).toHaveAttribute('type', 'text');
+});
+
+test('state', async () => {
+ const { component, getByPlaceholderText } = render(InputProjectId, { value: '' });
+ const input = getByPlaceholderText('Enter ID');
+
+ expect(component.value).toEqual('');
+ await userEvent.type(input, 'lorem');
+ expect(component.value).toEqual('lorem');
+});
+
+validStrings.forEach((validString) => {
+ test(`validates ${validString} as valid`, () => {
+ const { getByPlaceholderText } = render(InputProjectId, { value: validString });
+ const input = getByPlaceholderText('Enter ID') as HTMLInputElement;
+ expect(input.checkValidity()).toBe(true);
+ });
+});
+invalidStrings.forEach((invalidString) => {
+ test(`validates ${invalidString} as invalid`, () => {
+ const { getByPlaceholderText } = render(InputProjectId, { value: invalidString });
+ const input = getByPlaceholderText('Enter ID') as HTMLInputElement;
+ expect(input.checkValidity()).toBe(false);
+ });
+});