diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html
new file mode 100644
index 000000000..33c70f809
--- /dev/null
+++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.scss b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.scss
new file mode 100644
index 000000000..003ed84a8
--- /dev/null
+++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.scss
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@import 'src/theming/colors';
+@import 'src/theming/variables';
+
+.profile-form {
+ .field-container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 16px;
+ padding: 8px 16px 8px 24px;
+ }
+ .field-label {
+ margin: 0;
+ color: $grey-800;
+ font-size: 18px;
+ line-height: 24px;
+ }
+ mat-form-field {
+ width: 100%;
+ }
+}
+
+.form-actions {
+ display: flex;
+ gap: 16px;
+ padding: 0 24px;
+}
+
+.save-draft-button,
+.discard-button {
+ color: $primary;
+}
diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts
new file mode 100644
index 000000000..f72f41735
--- /dev/null
+++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.spec.ts
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ProfileFormComponent } from './profile-form.component';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+describe('ProfileFormComponent', () => {
+ let component: ProfileFormComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [ProfileFormComponent, BrowserAnimationsModule],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(ProfileFormComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ // TODO: Add more unit tests
+});
diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts
new file mode 100644
index 000000000..bb8e5b12e
--- /dev/null
+++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile-form.component.ts
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {
+ ChangeDetectionStrategy,
+ Component,
+ Input,
+ OnInit,
+} from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { CommonModule } from '@angular/common';
+import {
+ AbstractControl,
+ FormBuilder,
+ FormGroup,
+ ReactiveFormsModule,
+ Validators,
+} from '@angular/forms';
+import { MatInputModule } from '@angular/material/input';
+import { DeviceValidators } from '../../devices/components/device-form/device.validators';
+import { Profile } from '../../../model/profile';
+import { ProfileValidators } from './profile.validators';
+import { MatError } from '@angular/material/form-field';
+
+@Component({
+ selector: 'app-profile-form',
+ standalone: true,
+ imports: [
+ MatButtonModule,
+ CommonModule,
+ ReactiveFormsModule,
+ MatInputModule,
+ MatError,
+ ],
+ templateUrl: './profile-form.component.html',
+ styleUrl: './profile-form.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProfileFormComponent implements OnInit {
+ profileForm!: FormGroup;
+ @Input() profiles!: Profile[];
+ constructor(
+ private deviceValidators: DeviceValidators,
+ private profileValidators: ProfileValidators,
+ private fb: FormBuilder
+ ) {}
+
+ get nameControl() {
+ return this.profileForm.get('name') as AbstractControl;
+ }
+
+ ngOnInit() {
+ this.createProfileForm();
+ }
+
+ createProfileForm() {
+ this.profileForm = this.fb.group({
+ name: [
+ '',
+ [
+ Validators.required,
+ this.deviceValidators.deviceStringFormat(),
+ this.profileValidators.differentProfileName(this.profiles),
+ ],
+ ],
+ });
+ }
+}
diff --git a/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts b/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts
new file mode 100644
index 000000000..7de2cd353
--- /dev/null
+++ b/modules/ui/src/app/pages/risk-assessment/profile-form/profile.validators.ts
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Injectable } from '@angular/core';
+import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
+import { Profile } from '../../../model/profile';
+@Injectable({ providedIn: 'root' })
+export class ProfileValidators {
+ public differentProfileName(profiles: Profile[]): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ const value = control.value?.trim();
+ if (value && profiles.length) {
+ const isSameProfileName = this.hasSameProfileName(value, profiles);
+ return isSameProfileName ? { has_same_profile_name: true } : null;
+ }
+ return null;
+ };
+ }
+
+ private hasSameProfileName(
+ profileName: string,
+ profiles: Profile[]
+ ): boolean {
+ return (
+ profiles.some(profile => profile.name === profileName.trim()) || false
+ );
+ }
+}
diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.html b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.html
index 2cdd350b4..8975b819b 100644
--- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.html
+++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.html
@@ -14,14 +14,18 @@
limitations under the License.
-->
-
-
-
-