Change all usage of op-form-field` to spot-form-field

* `op-form-field` was used both as a BEM block as well as a component.
  This commit removes usages of `op-form-field` in both instances.
* It changes all usages of `opFormBinding` to `spotFormBinding`.
* It removes all old files related to `op-form-field`.
pull/11330/head
Benjamin Bädorf 3 years ago
parent c5313bee41
commit c1d0e02629
No known key found for this signature in database
GPG Key ID: 069CA2D117AB5CCF
  1. 2
      frontend/src/app/features/invite-user-modal/invite-user.component.sass
  2. 6
      frontend/src/app/features/invite-user-modal/message/message.component.html
  3. 2
      frontend/src/app/features/invite-user-modal/principal/principal-search.component.ts
  4. 10
      frontend/src/app/features/invite-user-modal/principal/principal.component.html
  5. 18
      frontend/src/app/features/invite-user-modal/project-selection/project-selection.component.html
  6. 2
      frontend/src/app/features/invite-user-modal/role/role-search.component.ts
  7. 12
      frontend/src/app/features/invite-user-modal/role/role.component.html
  8. 16
      frontend/src/app/features/invite-user-modal/summary/summary.component.html
  9. 4
      frontend/src/app/features/projects/components/new-project/new-project.component.html
  10. 8
      frontend/src/app/shared/components/dynamic-forms/components/dynamic-field-wrapper/dynamic-field-wrapper.component.html
  11. 24
      frontend/src/app/shared/components/forms/checkbox-field/checkbox-field.component.html
  12. 4
      frontend/src/app/shared/components/forms/checkbox-field/checkbox-field.component.ts
  13. 24
      frontend/src/app/shared/components/forms/form-field/form-binding.directive.ts
  14. 7
      frontend/src/app/shared/components/forms/form-field/form-field.children.sass
  15. 56
      frontend/src/app/shared/components/forms/form-field/form-field.component.html
  16. 78
      frontend/src/app/shared/components/forms/form-field/form-field.component.ts
  17. 53
      frontend/src/app/shared/components/forms/form-field/form-field.sass
  18. 2
      frontend/src/app/shared/components/forms/form.sass
  19. 1
      frontend/src/app/shared/components/forms/index.sass
  20. 6
      frontend/src/app/shared/shared.module.ts
  21. 22
      frontend/src/app/spot/components/form-field/form-field.component.html
  22. 10
      frontend/src/app/spot/components/form-field/form-field.component.ts
  23. 1
      frontend/src/app/spot/styles/sass/components/form-field.sass
  24. 20
      modules/github_integration/frontend/module/git-actions-menu/git-actions-menu.template.html
  25. 2
      spec/features/projects/attribute_help_texts_spec.rb
  26. 4
      spec/support/components/users/invite_user_modal.rb
  27. 2
      spec/support/form_fields/form_field.rb

@ -6,5 +6,5 @@
height: 100%
flex-grow: 1
.op-form-field + .op-form-field
.spot-form-field + .spot-form-field
margin-top: 1rem

@ -7,8 +7,8 @@
<div class="spot-divider"></div>
<div class="spot-modal--body op-form">
<op-form-field [label]="text.label">
<p class="op-form-field--description" slot="description">
<spot-form-field [label]="text.label">
<p class="spot-form-field--description" slot="description">
{{ text.description() }}
</p>
<textarea
@ -18,7 +18,7 @@
#input
autofocus>
</textarea>
</op-form-field>
</spot-form-field>
</div>
<div class="spot-modal--footer spot-action-bar">

@ -42,7 +42,7 @@ interface NgSelectPrincipalOption {
templateUrl: './principal-search.component.html',
})
export class PrincipalSearchComponent extends UntilDestroyedMixin implements OnInit {
@Input('opFormBinding') principalControl:FormControl;
@Input('spotFormBinding') principalControl:FormControl;
@Input() type:PrincipalType;

@ -6,14 +6,14 @@
<div class="spot-divider"></div>
<div class="spot-modal--body op-form">
<op-form-field
<div class="spot-modal--body spot-container">
<spot-form-field
[label]="textLabel"
required
>
<op-ium-principal-search
*ngIf="!(hasPrincipalSelected && isNewPrincipal)"
[opFormBinding]="principalControl"
[spotFormBinding]="principalControl"
[type]="type"
[project]="project"
slot="input"
@ -46,12 +46,12 @@
<div
slot="errors"
class="op-form-field--error"
class="spot-form-field--error"
*ngIf="principalControl?.touched && principalControl?.invalid"
>
{{ text.required[type] }}
</div>
</op-form-field>
</spot-form-field>
<op-dynamic-form
*ngIf="isNewPrincipal && type === PrincipalType.User && userDynamicFieldConfig.schema"

@ -6,8 +6,8 @@
<div class="spot-divider"></div>
<div class="spot-modal--body op-form">
<op-form-field
<div class="spot-modal--body spot-container">
<spot-form-field
[label]="text.project.label"
required
>
@ -28,7 +28,7 @@
<div
slot="errors"
class="op-form-field--error"
class="spot-form-field--error"
*ngIf="projectControl.errors?.required"
>
{{ text.project.required }}
@ -36,14 +36,14 @@
<div
slot="errors"
class="op-form-field--error"
class="spot-form-field--error"
*ngIf="projectControl.errors?.lackingPermission"
>
{{ text.project.lackingPermission }}
</div>
</op-form-field>
</spot-form-field>
<op-form-field>
<spot-form-field>
<op-option-list
[options]="typeOptions"
formControlName="type"
@ -52,14 +52,14 @@
<div
*ngIf="projectAndTypeForm?.dirty && typeControl?.invalid"
class="op-form-field--errors"
class="spot-form-field--errors"
slot="errors"
>
<div class="op-form-field--error">
<div class="spot-form-field--error">
{{ text.type.required }}
</div>
</div>
</op-form-field>
</spot-form-field>
</div>
<div class="spot-modal--footer spot-action-bar">

@ -19,7 +19,7 @@ import { ApiV3FilterBuilder } from 'core-app/shared/helpers/api-v3/api-v3-filter
templateUrl: './role-search.component.html',
})
export class RoleSearchComponent extends UntilDestroyedMixin implements OnInit {
@Input('opFormBinding') roleControl:FormControl;
@Input('spotFormBinding') roleControl:FormControl;
public input$ = new Subject<string|null>();

@ -6,29 +6,29 @@
<div class="spot-divider"></div>
<div class="spot-modal--body op-form">
<op-form-field
<div class="spot-modal--body spot-container">
<spot-form-field
[label]="text.label()"
required
>
<p
class="op-form-field--description"
class="spot-form-field--description"
slot="description"
[innerHtml]="text.description()"
></p>
<op-ium-role-search
[opFormBinding]="roleControl"
[spotFormBinding]="roleControl"
slot="input"
></op-ium-role-search>
<div
slot="errors"
class="op-form-field--error"
class="spot-form-field--error"
*ngIf="roleControl?.touched && roleControl?.invalid"
>
{{ text.required }}
</div>
</op-form-field>
</spot-form-field>
</div>
<div class="spot-modal--footer spot-action-bar">

@ -7,24 +7,24 @@
<div class="spot-divider"></div>
<div class="spot-modal--body op-form">
<div class="spot-modal--body spot-container">
<op-form-field [label]="text.projectLabel">
<p slot="input">{{ project.name }}</p>
</op-form-field>
</spot-form-field>
<div class="op-ium-summary__row">
<op-form-field [label]="text.principalLabel[type]">
<spot-form-field [label]="text.principalLabel[type]">
<p slot="input">{{ principal?.name }}</p>
</op-form-field>
<op-form-field [label]="text.roleLabel()">
</spot-form-field>
<spot-form-field [label]="text.roleLabel()">
<p slot="input">{{ role.name }}</p>
</op-form-field>
</spot-form-field>
</div>
<op-form-field
<spot-form-field
[label]="text.messageLabel"
*ngIf="type !== PrincipalType.Placeholder && message"
>
<p slot="input" class="op-ium-summary-message">{{ message }}</p>
</op-form-field>
</spot-form-field>
</div>
<div class="spot-modal--footer spot-action-bar">

@ -3,7 +3,7 @@
[formGroup]="templateForm"
>
<div [ngClass]="{ 'op-highlighted-input': true, 'op-highlighted-input_active': !!templateControl?.value }">
<op-form-field
<spot-form-field
[label]="text.use_template"
data-qa-field-name="use_template"
>
@ -16,7 +16,7 @@
slot="input"
>
</ng-select>
</op-form-field>
</spot-form-field>
</div>
</form>

@ -1,4 +1,4 @@
<op-form-field
<spot-form-field
*ngIf="field.type !== 'booleanInput'"
[control]="field?.formControl"
[label]="to?.label"
@ -13,11 +13,11 @@
<ng-container #fieldComponent slot="input"></ng-container>
<formly-validation-message
class="op-form-field--error"
class="spot-form-field--error"
[field]="field"
slot="errors"
></formly-validation-message>
</op-form-field>
</spot-form-field>
<op-checkbox-field
*ngIf="field.type === 'booleanInput'"
@ -33,7 +33,7 @@
<ng-container #fieldComponent slot="input"></ng-container>
<formly-validation-message
class="op-form-field--error"
class="spot-form-field--error"
[field]="field"
slot="errors"
></formly-validation-message>

@ -1,7 +1,7 @@
<ng-container *ngIf="!hidden">
<label class="op-form-field--label-wrap op-checkbox-field--label-wrap">
<label class="spot-form-field--label-wrap op-checkbox-field--label-wrap">
<div
class="op-form-field--input op-checkbox-field--input"
class="spot-form-field--input op-checkbox-field--input"
[attr.aria-describedby]="describedByID"
>
<ng-content select="[slot=input]"></ng-content>
@ -9,34 +9,30 @@
<div
*ngIf="label"
class="op-form-field--label op-checkbox-field--label"
class="spot-form-field--label op-checkbox-field--label"
>
<span
*ngIf="showErrorMessage"
class="Hidden for sighted"
>Invalid</span>
{{ label }}
<span *ngIf="required" class="op-form-field--label-indicator">*</span>
<span *ngIf="required" class="spot-form-field--label-indicator">*</span>
<attribute-help-text
[attribute]="helpTextAttribute"
[attributeScope]="helpTextAttributeScope"
></attribute-help-text>
</div>
<div
class="op-form-field--description op-checkbox-field--description"
[id]="descriptionID"
>
<ng-content select="[slot=description]"></ng-content>
</div>
</label>
<div class="op-form-field--help-text">
<ng-content select="[slot=help-text]"></ng-content>
<div
class="spot-form-field--description"
[id]="descriptionID"
>
<ng-content select="[slot=description]"></ng-content>
</div>
<div
class="op-form-field--errors"
class="spot-form-field--errors"
*ngIf="showErrorMessage"
[id]="errorsID"
>

@ -16,11 +16,11 @@ import {
templateUrl: './checkbox-field.component.html',
})
export class OpCheckboxFieldComponent {
@HostBinding('class.op-form-field') className = true;
@HostBinding('class.spot-form-field') className = true;
@HostBinding('class.op-checkbox-field') classNameCheckbox = true;
@HostBinding('class.op-form-field_invalid') get errorClassName():boolean {
@HostBinding('class.spot-form-field_invalid') get errorClassName():boolean {
return this.showErrorMessage;
}

@ -1,24 +0,0 @@
import { Directive, forwardRef, Input } from '@angular/core';
import {
FormArray, FormControl, FormGroup, NgControl,
} from '@angular/forms';
export const formControlBinding:any = {
provide: NgControl,
useExisting: forwardRef(() => OpFormBindingDirective),
};
@Directive({
selector: '[opFormBinding]',
providers: [formControlBinding],
exportAs: 'ngForm',
})
export class OpFormBindingDirective extends NgControl {
@Input('opFormBinding') form!:FormControl|FormGroup|FormArray;
get control():FormControl|FormGroup|FormArray {
return this.form;
}
viewToModelUpdate():void {}
}

@ -1,7 +0,0 @@
.op-form-field_invalid
.ng-select-container,
.op-input,
.op-option-list--item,
.document-editor__editable-container,
.ck.ck-toolbar
border-color: var(--content-form-error-color)

@ -1,56 +0,0 @@
<ng-container *ngIf="!hidden">
<label class="op-form-field--label-wrap">
<div class="op-form-field--label">
<span
*ngIf="showErrorMessage"
class="hidden-for-sighted"
>
{{ text.invalid }}
</span>
{{ label }}
<span *ngIf="required" class="op-form-field--label-indicator">*</span>
<attribute-help-text
[attribute]="helpTextAttribute"
[attributeScope]="helpTextAttributeScope"
></attribute-help-text>
</div>
<ng-container *ngIf="!noWrapLabel">
<ng-container *ngTemplateOutlet="inputTemplate"></ng-container>
</ng-container>
</label>
<ng-container *ngIf="noWrapLabel">
<ng-container *ngTemplateOutlet="inputTemplate"></ng-container>
</ng-container>
<div class="op-form-field--help-text">
<ng-content select="[slot=help-text]"></ng-content>
</div>
<div
class="op-form-field--errors"
*ngIf="showErrorMessage"
[id]="errorsID"
>
<ng-content select="[slot=errors]"></ng-content>
</div>
</ng-container>
<ng-template #inputTemplate>
<div
class="op-form-field--description"
[id]="descriptionID"
>
<ng-content select="[slot=description]"></ng-content>
</div>
<div
class="op-form-field--input"
[attr.aria-describedby]="describedByID"
>
<ng-content select="[slot=input]"></ng-content>
</div>
</ng-template>

@ -1,78 +0,0 @@
import {
Component, ContentChild, HostBinding, Input, Optional,
} from '@angular/core';
import { AbstractControl, FormGroupDirective, NgControl } from '@angular/forms';
import { I18nService } from 'core-app/core/i18n/i18n.service';
@Component({
selector: 'op-form-field',
templateUrl: './form-field.component.html',
})
export class OpFormFieldComponent {
@HostBinding('class.op-form-field') className = true;
@HostBinding('class.op-form-field_invalid') get errorClassName() {
return this.showErrorMessage;
}
@Input() label = '';
@Input() noWrapLabel = false;
@Input() required = false;
@Input() hidden = false;
@Input() showValidationErrorOn:'change' | 'blur' | 'submit' | 'never' = 'submit';
@Input() control?:AbstractControl;
@Input() helpTextAttribute?:string;
@Input() helpTextAttributeScope?:string;
@ContentChild(NgControl) ngControl:NgControl;
internalID = `op-form-field-${+new Date()}`;
text = {
invalid: this.I18n.t('js.label_invalid'),
};
get errorsID() {
return `${this.internalID}-errors`;
}
get descriptionID() {
return `${this.internalID}-description`;
}
get describedByID() {
return this.showErrorMessage ? this.errorsID : this.descriptionID;
}
get formControl():AbstractControl|undefined|null {
return this.ngControl?.control || this.control;
}
get showErrorMessage():boolean {
if (!this.formControl) {
return false;
}
if (this.showValidationErrorOn === 'submit') {
return this.formControl.invalid && this._formGroupDirective?.submitted;
} if (this.showValidationErrorOn === 'blur') {
return this.formControl.invalid && this.formControl.touched;
} if (this.showValidationErrorOn === 'change') {
return this.formControl.invalid && this.formControl.dirty;
}
return false;
}
constructor(
@Optional() private _formGroupDirective:FormGroupDirective,
readonly I18n:I18nService,
) {}
}

@ -1,53 +0,0 @@
@import 'form-field.children'
.op-form-field
display: flex
flex-direction: column
line-height: 1.6rem
// This is a fix for the formly-forms, which render the wrapper around a non-visible input
&:empty
display: none
&--label,
&--description,
&--input,
&--help-text
margin-bottom: 0.5rem
&--label-wrap
display: flex
flex-direction: column
margin: 0
&--label
font-size: 1rem
font-weight: bold
&-indicator
color: var(--primary-color)
&_invalid &--label
color: var(--content-form-error-color)
&--description,
&--help-text
font-size: 12px
&--description *:last-child
margin-bottom: 0
&--errors
display: flex
flex-direction: column
&--error
color: var(--content-form-error-color)
margin-bottom: 1rem
font-size: 0.8rem
&--description,
&--help-text,
&--errors
&:empty
display: none

@ -17,7 +17,7 @@
&--section-header,
> .op-form--fieldset,
> .op-form--field,
> .op-form-field,
> .spot-form-field,
> .op-checkbox-field,
> .op-option-list,
> .op-highlighted-input,

@ -1,4 +1,3 @@
@import './form-field/form-field'
@import './checkbox-field/checkbox-field'
@import './form'
@import './fieldset'

@ -79,8 +79,6 @@ import { ShowSectionDropdownComponent } from './components/hide-section/show-sec
import { SlideToggleComponent } from './components/slide-toggle/slide-toggle.component';
import { DynamicBootstrapModule } from './components/dynamic-bootstrap/dynamic-bootstrap.module';
import { OpCheckboxFieldComponent } from './components/forms/checkbox-field/checkbox-field.component';
import { OpFormFieldComponent } from './components/forms/form-field/form-field.component';
import { OpFormBindingDirective } from './components/forms/form-field/form-binding.directive';
import { OpOptionListComponent } from './components/option-list/option-list.component';
import { OpSidemenuComponent } from './components/sidemenu/sidemenu.component';
import { OpProjectIncludeComponent } from './components/project-include/project-include.component';
@ -194,8 +192,6 @@ export function bootstrapModule(injector:Injector):void {
SlideToggleComponent,
OpCheckboxFieldComponent,
OpFormFieldComponent,
OpFormBindingDirective,
OpOptionListComponent,
OpSidemenuComponent,
OpProjectIncludeComponent,
@ -255,8 +251,6 @@ export function bootstrapModule(injector:Injector):void {
SlideToggleComponent,
OpCheckboxFieldComponent,
OpFormFieldComponent,
OpFormBindingDirective,
OpOptionListComponent,
OpSidemenuComponent,
OpProjectIncludeComponent,

@ -3,10 +3,14 @@
<div class="spot-form-field--label">
<span
*ngIf="showErrorMessage"
class="Hidden for sighted"
>Invalid</span>
class="hidden-for-sighted"
>
{{ text.invalid }}
</span>
{{ label }}
<span *ngIf="required" class="spot-form-field--label-indicator">*</span>
<attribute-help-text
[attribute]="helpTextAttribute"
[attributeScope]="helpTextAttributeScope"
@ -22,11 +26,8 @@
<ng-container *ngTemplateOutlet="inputTemplate"></ng-container>
</ng-container>
<div
class="spot-form-field--description"
[id]="descriptionID"
>
<ng-content select="[slot=description]"></ng-content>
<div class="spot-form-field--help-text">
<ng-content select="[slot=help-text]"></ng-content>
</div>
<div
@ -39,6 +40,13 @@
</ng-container>
<ng-template #inputTemplate>
<div
class="spot-form-field--description"
[id]="descriptionID"
>
<ng-content select="[slot=description]"></ng-content>
</div>
<div
class="spot-form-field--input"
[attr.aria-describedby]="describedByID"

@ -2,6 +2,7 @@ import {
Component, ContentChild, HostBinding, Input, Optional,
} from '@angular/core';
import { AbstractControl, FormGroupDirective, NgControl } from '@angular/forms';
import { I18nService } from 'core-app/core/i18n/i18n.service';
@Component({
selector: 'spot-form-field',
@ -22,18 +23,22 @@ export class SpotFormFieldComponent {
@Input() hidden = false;
@Input() showValidationErrorOn:'change' | 'blur' | 'submit' | 'never' = 'submit';
@Input() control?:AbstractControl;
@Input() helpTextAttribute?:string;
@Input() helpTextAttributeScope?:string;
@Input() showValidationErrorOn:'change' | 'blur' | 'submit' | 'never' = 'submit';
@ContentChild(NgControl) ngControl:NgControl;
internalID = `spot-form-field-${+new Date()}`;
text = {
invalid: this.I18n.t('js.label_invalid'),
};
get errorsID() {
return `${this.internalID}-errors`;
}
@ -68,5 +73,6 @@ export class SpotFormFieldComponent {
constructor(
@Optional() private _formGroupDirective:FormGroupDirective,
readonly I18n:I18nService,
) {}
}

@ -42,6 +42,7 @@
margin-bottom: 1rem
font-size: 0.8rem
&--label,
&--description,
&--errors
&:empty

@ -1,16 +1,18 @@
<div class="git-actions-menu dropdown-relative dropdown -overflow-in-view dropdown-anchor-right">
<h3 class="title">{{text.title}}</h3>
<div class="copy-wrapper op-form-field" *ngFor="let snippet of snippets">
<label class="op-form-field--label-wrap">
<div class="op-form-field--label">{{ snippet.name }}</div>
<div class="op-form-field--input">
<div class="copy-wrapper spot-form-field" *ngFor="let snippet of snippets">
<label class="spot-form-field--label-wrap">
<div class="spot-form-field--label">{{ snippet.name }}</div>
<div class="spot-form-field--input">
<input type="text" class="copy-content op-input" readonly="true" [value]="snippet.textToCopy()">
<button class="button copy-button"
type="button"
[attr.aria-label]="text.copyButtonHelpText"
(click)="onCopyButtonClick(snippet)">
<op-icon icon-classes="button--icon icon-copy"></op-icon>
<button
class="button copy-button"
type="button"
[attr.aria-label]="text.copyButtonHelpText"
(click)="onCopyButtonClick(snippet)"
>
<span class="spot-icon spot-icon_copy"></span>
</button>
<div class="copy-result-message" *ngIf="showCopyResult && snippet.id === copiedSnippetId" [textContent]="lastCopyResult"></div>
</div>

@ -89,7 +89,7 @@ describe 'Project attribute help texts', type: :feature, js: true do
page.find('.op-fieldset--legend', text: 'ADVANCED SETTINGS').click
expect(page).to have_selector('.op-form-field--label attribute-help-text', wait: 10)
expect(page).to have_selector('.spot-form-field--label attribute-help-text', wait: 10)
# Open help text modal
modal.open!

@ -183,14 +183,14 @@ module Components
def expect_error_displayed(message)
within_modal do
expect(page)
.to have_selector('.op-form-field--error', text: message)
.to have_selector('.spot-form-field--error', text: message)
end
end
def expect_help_displayed(message)
within_modal do
expect(page)
.to have_selector('.op-form-field--help-text', text: message)
.to have_selector('.spot-form-field--help-text', text: message)
end
end
end

@ -16,7 +16,7 @@ module FormFields
def expect_required
expect(field_container)
.to have_selector '.op-form-field--label-indicator', text: '*'
.to have_selector '.spot-form-field--label-indicator', text: '*'
end
def field_container

Loading…
Cancel
Save