diff --git a/config/locales/js-en.yml b/config/locales/js-en.yml index 8fe7fa7a965..32e811af821 100644 --- a/config/locales/js-en.yml +++ b/config/locales/js-en.yml @@ -446,6 +446,7 @@ en: label_quote_comment: "Quote this comment" label_recent: "Recent" label_reset: "Reset" + label_remove: "Remove" label_remove_column: "Remove column" label_remove_columns: "Remove selected columns" label_remove_row: "Remove row" diff --git a/frontend/doc/TESTING.md b/frontend/doc/TESTING.md index de01f2b3777..932c4458d63 100644 --- a/frontend/doc/TESTING.md +++ b/frontend/doc/TESTING.md @@ -11,8 +11,7 @@ OpenProject is a hybrid application with most parts being Rails, along with some -The Angular frontend services and components can be tested with frontend specs. A good isolated example on how to set up an Angular TestBed to test components is `frontend/src/app/modules/a11y/accessible-by-keyboard.component.spec.ts` - +The Angular frontend services and components can be tested with frontend specs. If you want to test services that have no dependencies, a simple instantiation of that class is sufficient to test the service in isolation. A good example is ` frontend/src/app/components/projects/current-project.service.spec.ts` \ No newline at end of file diff --git a/frontend/src/app/components/filters/query-filter/query-filter.component.html b/frontend/src/app/components/filters/query-filter/query-filter.component.html index 1d3c6aa4bbb..c6c2d300694 100644 --- a/frontend/src/app/components/filters/query-filter/query-filter.component.html +++ b/frontend/src/app/components/filters/query-filter/query-filter.component.html @@ -1,87 +1,115 @@ - diff --git a/frontend/src/app/components/work-packages/work-package-comment/work-package-comment.component.html b/frontend/src/app/components/work-packages/work-package-comment/work-package-comment.component.html index 5752120eb0c..373e08371fe 100644 --- a/frontend/src/app/components/work-packages/work-package-comment/work-package-comment.component.html +++ b/frontend/src/app/components/work-packages/work-package-comment/work-package-comment.component.html @@ -3,36 +3,42 @@ -
+
- + -
- - - - +
+
-
+
diff --git a/frontend/src/app/components/work-packages/wp-breadcrumb/wp-breadcrumb-parent.html b/frontend/src/app/components/work-packages/wp-breadcrumb/wp-breadcrumb-parent.html index 8e851cce35c..2d1a1dcb77d 100644 --- a/frontend/src/app/components/work-packages/wp-breadcrumb/wp-breadcrumb-parent.html +++ b/frontend/src/app/components/work-packages/wp-breadcrumb/wp-breadcrumb-parent.html @@ -6,19 +6,25 @@ class="wp-breadcrumb-parent breadcrumb-project-title nocut"> - + +
- - - - - - + +
- - - +
diff --git a/frontend/src/app/components/wp-relations/wp-relation-row/wp-relation-row.template.html b/frontend/src/app/components/wp-relations/wp-relation-row/wp-relation-row.template.html index 766a2ade34a..590361d1dd9 100644 --- a/frontend/src/app/components/wp-relations/wp-relation-row/wp-relation-row.template.html +++ b/frontend/src/app/components/wp-relations/wp-relation-row/wp-relation-row.template.html @@ -1,6 +1,6 @@
+ focus-within="'.wp-relations-controls-section button'">
@@ -49,22 +49,26 @@
- - - - - - + +
diff --git a/frontend/src/app/components/wp-relations/wp-relations-create/wp-relation-create.template.html b/frontend/src/app/components/wp-relations/wp-relations-create/wp-relation-create.template.html index ed07655c4cb..631bfd49488 100644 --- a/frontend/src/app/components/wp-relations/wp-relations-create/wp-relation-create.template.html +++ b/frontend/src/app/components/wp-relations/wp-relations-create/wp-relation-create.template.html @@ -42,12 +42,13 @@
- - - +
diff --git a/frontend/src/app/components/wp-relations/wp-relations-group/wp-relations-group.template.html b/frontend/src/app/components/wp-relations/wp-relations-group/wp-relations-group.template.html index 4d622937c01..2e738807791 100644 --- a/frontend/src/app/components/wp-relations/wp-relations-group/wp-relations-group.template.html +++ b/frontend/src/app/components/wp-relations/wp-relations-group/wp-relations-group.template.html @@ -7,13 +7,15 @@
- +
diff --git a/frontend/src/app/components/wp-single-view-tabs/activity-panel/activity-tab.html b/frontend/src/app/components/wp-single-view-tabs/activity-panel/activity-tab.html index 40f079a838d..0d2222d16f3 100644 --- a/frontend/src/app/components/wp-single-view-tabs/activity-panel/activity-tab.html +++ b/frontend/src/app/components/wp-single-view-tabs/activity-panel/activity-tab.html @@ -8,12 +8,14 @@ [ngClass]="{'-with-toggler': first && showToggler}" *ngIf="first || inf.isNextDate"> - - - + + diff --git a/frontend/src/app/components/wp-table/config-menu/config-menu.template.html b/frontend/src/app/components/wp-table/config-menu/config-menu.template.html index 5e33ee5f13b..aeb0a59d1b9 100644 --- a/frontend/src/app/components/wp-table/config-menu/config-menu.template.html +++ b/frontend/src/app/components/wp-table/config-menu/config-menu.template.html @@ -1,7 +1,8 @@ - - - + diff --git a/frontend/src/app/components/wp-tabs/components/wp-tabs/wp-tabs.component.html b/frontend/src/app/components/wp-tabs/components/wp-tabs/wp-tabs.component.html index 9001276f010..e55adf4742d 100644 --- a/frontend/src/app/components/wp-tabs/components/wp-tabs/wp-tabs.component.html +++ b/frontend/src/app/components/wp-tabs/components/wp-tabs/wp-tabs.component.html @@ -3,24 +3,24 @@ class="op-work-package-tabs">
  • - - + +
  • - - + +
  • diff --git a/frontend/src/app/components/wp-tabs/wp-tabs.module.ts b/frontend/src/app/components/wp-tabs/wp-tabs.module.ts index aeffb7a91b8..d89850d78b9 100644 --- a/frontend/src/app/components/wp-tabs/wp-tabs.module.ts +++ b/frontend/src/app/components/wp-tabs/wp-tabs.module.ts @@ -6,6 +6,7 @@ import { WpTabWrapperComponent } from "core-components/wp-tabs/components/wp-tab import { DynamicModule } from "ng-dynamic-component"; import { OpenprojectAccessibilityModule } from "core-app/modules/a11y/openproject-a11y.module"; import { OpenprojectTabsModule } from "core-app/modules/common/tabs/openproject-tabs.module"; +import { IconModule } from "core-app/modules/icon/icon.module"; @NgModule({ declarations: [ @@ -17,7 +18,8 @@ import { OpenprojectTabsModule } from "core-app/modules/common/tabs/openproject- UIRouterModule, DynamicModule, OpenprojectAccessibilityModule, - OpenprojectTabsModule + OpenprojectTabsModule, + IconModule ], exports: [ WpTabsComponent, diff --git a/frontend/src/app/modules/a11y/accessible-by-keyboard.component.spec.ts b/frontend/src/app/modules/a11y/accessible-by-keyboard.component.spec.ts deleted file mode 100644 index b880a928b12..00000000000 --- a/frontend/src/app/modules/a11y/accessible-by-keyboard.component.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -//-- copyright -// OpenProject is an open source project management software. -// Copyright (C) 2012-2021 the OpenProject GmbH -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2013 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See docs/COPYRIGHT.rdoc for more details. -//++ - -import { AccessibleByKeyboardComponent } from "core-app/modules/a11y/accessible-by-keyboard.component"; - -import { ComponentFixture, TestBed } from '@angular/core/testing'; - - -describe('accessibleByKeyboard component', () => { - beforeEach((() => { - - // noinspection JSIgnoredPromiseFromCall - TestBed.configureTestingModule({ - declarations: [ - AccessibleByKeyboardComponent - ] - }).compileComponents(); - })); - - describe('inner element', function() { - let app:AccessibleByKeyboardComponent; - let fixture:ComponentFixture; - let element:HTMLElement; - - it('should render an inner link with specified classes', function() { - fixture = TestBed.createComponent(AccessibleByKeyboardComponent); - app = fixture.debugElement.componentInstance; - element = fixture.elementRef.nativeElement; - - app.linkClass = 'a-link-class'; - app.spanClass = 'a-span-class'; - fixture.detectChanges(); - - const link = element.querySelector('a')!; - const span = element.querySelector('a > span')!; - expect(link.classList.contains('a-link-class')).toBeTruthy(); - expect(span.classList.contains('a-span-class')).toBeTruthy(); - }); - }); -}); - - - diff --git a/frontend/src/app/modules/a11y/accessible-by-keyboard.component.ts b/frontend/src/app/modules/a11y/accessible-by-keyboard.component.ts deleted file mode 100644 index 95be34a1664..00000000000 --- a/frontend/src/app/modules/a11y/accessible-by-keyboard.component.ts +++ /dev/null @@ -1,62 +0,0 @@ -//-- copyright -// OpenProject is an open source project management software. -// Copyright (C) 2012-2021 the OpenProject GmbH -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2013 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See docs/COPYRIGHT.rdoc for more details. -//++ - -import { Component, EventEmitter, Input, Output } from '@angular/core'; - -@Component({ - selector: 'accessible-by-keyboard', - template: ` - - - - - - ` -}) -export class AccessibleByKeyboardComponent { - @Output() execute = new EventEmitter(); - @Input() isDisabled:boolean; - @Input() linkClass:string; - @Input() linkTitle:string; - @Input() spanClass:string; - @Input() linkAriaLabel:string; - - public handleClick(event:JQuery.TriggeredEvent) { - if (!this.isDisabled) { - this.execute.emit(event); - } - - return false; - } -} diff --git a/frontend/src/app/modules/a11y/openproject-a11y.module.ts b/frontend/src/app/modules/a11y/openproject-a11y.module.ts index 6805e8ae8be..411f800eed4 100644 --- a/frontend/src/app/modules/a11y/openproject-a11y.module.ts +++ b/frontend/src/app/modules/a11y/openproject-a11y.module.ts @@ -31,7 +31,6 @@ import { NgModule } from "@angular/core"; import { FormsModule } from "@angular/forms"; import { CommonModule } from "@angular/common"; import { AccessibleClickDirective } from "core-app/modules/a11y/accessible-click.directive"; -import { AccessibleByKeyboardComponent } from "core-app/modules/a11y/accessible-by-keyboard.component"; import { DoubleClickOrTapDirective } from "core-app/modules/a11y/double-click-or-tap.directive"; @NgModule({ @@ -42,12 +41,10 @@ import { DoubleClickOrTapDirective } from "core-app/modules/a11y/double-click-or exports: [ AccessibleClickDirective, DoubleClickOrTapDirective, - AccessibleByKeyboardComponent, ], declarations: [ AccessibleClickDirective, DoubleClickOrTapDirective, - AccessibleByKeyboardComponent, ] }) export class OpenprojectAccessibilityModule { diff --git a/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.html b/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.html index c4bcc52ade6..df783e649de 100644 --- a/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.html +++ b/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.html @@ -1,7 +1,11 @@ - - - {{ additionalLabel }} - + diff --git a/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.ts b/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.ts index 9704540d5b1..01955fc5a49 100644 --- a/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.ts +++ b/frontend/src/app/modules/attribute-help-texts/attribute-help-text.component.ts @@ -93,10 +93,12 @@ export class AttributeHelpTextComponent implements OnInit { } } - public handleClick() { + public handleClick(event:Event):void { this.load().then((resource) => { this.opModalService.show(AttributeHelpTextModal, this.injector, { helpText: resource }); }); + + event.preventDefault(); } private load() { diff --git a/frontend/src/app/modules/boards/index-page/boards-index-page.component.html b/frontend/src/app/modules/boards/index-page/boards-index-page.component.html index 7e42408c485..50fb125dc9a 100644 --- a/frontend/src/app/modules/boards/index-page/boards-index-page.component.html +++ b/frontend/src/app/modules/boards/index-page/boards-index-page.component.html @@ -91,11 +91,13 @@ - - {{ text.delete }} - + diff --git a/frontend/src/app/modules/common/back-routing/back-button.component.html b/frontend/src/app/modules/common/back-routing/back-button.component.html new file mode 100644 index 00000000000..8b0f2b80ed5 --- /dev/null +++ b/frontend/src/app/modules/common/back-routing/back-button.component.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/frontend/src/app/modules/common/back-routing/back-button.component.sass b/frontend/src/app/modules/common/back-routing/back-button.component.sass new file mode 100644 index 00000000000..61314bf11ff --- /dev/null +++ b/frontend/src/app/modules/common/back-routing/back-button.component.sass @@ -0,0 +1,18 @@ +.op-back-button + padding: 0 + line-height: 32px + margin: 0 1rem 0 0 + width: 75px + height: 34px + + &--icon + font-size: 1rem + line-height: 22px + + @media only screen and (max-width: 679px) + // Move button in the current reverse order to front + position: absolute + top: 0 + left: 0 + z-index: 1 + width: 100% \ No newline at end of file diff --git a/frontend/src/app/modules/common/back-routing/back-button.component.ts b/frontend/src/app/modules/common/back-routing/back-button.component.ts index c63566447c8..395af25e51f 100644 --- a/frontend/src/app/modules/common/back-routing/back-button.component.ts +++ b/frontend/src/app/modules/common/back-routing/back-button.component.ts @@ -31,22 +31,14 @@ import { BackRoutingService } from "core-app/modules/common/back-routing/back-ro import { I18nService } from "core-app/modules/common/i18n/i18n.service"; @Component({ - template: ` -
    - - - -
    - `, + templateUrl: './back-button.component.html', + styleUrls: ['./back-button.component.sass'], changeDetection: ChangeDetectionStrategy.OnPush, - selector: 'back-button', + selector: 'op-back-button', }) export class BackButtonComponent { @Input() public linkClass:string; - @Input() public customBackMethod:Function; + @Input() public customBackMethod:() => unknown; public text = { goBack: this.I18n.t('js.button_back') @@ -56,18 +48,11 @@ export class BackButtonComponent { readonly I18n:I18nService) { } - public goBack() { + public goBack():void { if (this.customBackMethod) { this.customBackMethod(); } else { this.backRoutingService.goBack(); } } - - public classes():string { - let classes = 'button '; - classes += this.linkClass ? this.linkClass : ''; - - return classes; - } } diff --git a/frontend/src/app/modules/common/collapsible-section/collapsible-section.component.ts b/frontend/src/app/modules/common/collapsible-section/collapsible-section.component.ts index 813c8154750..509a8a5858d 100644 --- a/frontend/src/app/modules/common/collapsible-section/collapsible-section.component.ts +++ b/frontend/src/app/modules/common/collapsible-section/collapsible-section.component.ts @@ -57,7 +57,8 @@ export class CollapsibleSectionComponent implements OnInit { target.removeAttribute('hidden'); } - public toggle() { + public toggle(event:Event) { this.expanded = !this.expanded; + event.preventDefault(); } } diff --git a/frontend/src/app/modules/common/collapsible-section/collapsible-section.html b/frontend/src/app/modules/common/collapsible-section/collapsible-section.html index 5755f5d20c8..a9c0b45b3e0 100644 --- a/frontend/src/app/modules/common/collapsible-section/collapsible-section.html +++ b/frontend/src/app/modules/common/collapsible-section/collapsible-section.html @@ -1,12 +1,14 @@
    - - - +
    diff --git a/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.html b/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.html index 6749532460d..9041c1292e4 100644 --- a/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.html +++ b/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.html @@ -1,6 +1,8 @@ - - - + \ No newline at end of file diff --git a/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.ts b/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.ts index 2610d91125d..f59b1ee8270 100644 --- a/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.ts +++ b/frontend/src/app/modules/common/hide-section/hide-section-link/hide-section-link.component.ts @@ -28,6 +28,7 @@ import { Component, ElementRef, OnInit } from "@angular/core"; import { HideSectionService } from "core-app/modules/common/hide-section/hide-section.service"; +import { I18nService } from "core-app/modules/common/i18n/i18n.service"; export const hideSectionLinkSelector = 'hide-section-link'; @@ -40,8 +41,13 @@ export class HideSectionLinkComponent implements OnInit { public sectionName:string; + text = { + remove: this.I18n.t('js.label_remove') + } + constructor(protected elementRef:ElementRef, - protected hideSectionService:HideSectionService) {} + protected hideSectionService:HideSectionService, + protected I18n:I18nService) {} ngOnInit():void { this.sectionName = this.elementRef.nativeElement.dataset.sectionName; diff --git a/frontend/src/app/modules/common/link/link.sass b/frontend/src/app/modules/common/link/link.sass index 811eedcb148..f1b8a2d6286 100644 --- a/frontend/src/app/modules/common/link/link.sass +++ b/frontend/src/app/modules/common/link/link.sass @@ -16,4 +16,8 @@ &:focus color: var(--content-link-hover-active-color) - + + // Ensure op-icon within a link gets inline-block + // to avoid it receiving any text-decoration on hover + .op-icon--wrapper + display: inline-block diff --git a/frontend/src/app/modules/common/notifications/notification.component.html b/frontend/src/app/modules/common/notifications/notification.component.html index 3d371c6d191..7401acfc1f7 100644 --- a/frontend/src/app/modules/common/notifications/notification.component.html +++ b/frontend/src/app/modules/common/notifications/notification.component.html @@ -39,9 +39,13 @@
    - - + diff --git a/frontend/src/app/modules/fields/edit/field-controls/edit-field-controls.component.html b/frontend/src/app/modules/fields/edit/field-controls/edit-field-controls.component.html index 6c6346610fe..044542d4d09 100644 --- a/frontend/src/app/modules/fields/edit/field-controls/edit-field-controls.component.html +++ b/frontend/src/app/modules/fields/edit/field-controls/edit-field-controls.component.html @@ -1,15 +1,21 @@
    - - - - - - + +
    diff --git a/frontend/src/app/modules/invite-user-modal/principal/principal.component.html b/frontend/src/app/modules/invite-user-modal/principal/principal.component.html index 74bf75330b0..d100999d87c 100644 --- a/frontend/src/app/modules/invite-user-modal/principal/principal.component.html +++ b/frontend/src/app/modules/invite-user-modal/principal/principal.component.html @@ -24,6 +24,7 @@ > {{ text.inviteUser }} {{ principal.name }} @@ -35,6 +36,7 @@ > {{ text.createNewPlaceholder }} {{ principal.name }} diff --git a/frontend/src/app/modules/work_packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html b/frontend/src/app/modules/work_packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html index 7d240a306db..867dc0ba6e7 100644 --- a/frontend/src/app/modules/work_packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html +++ b/frontend/src/app/modules/work_packages/routing/partitioned-query-space-page/partitioned-query-space-page.component.html @@ -2,10 +2,10 @@ [ngClass]="currentPartition">
    - - +
    - +
    diff --git a/frontend/src/app/modules/work_packages/routing/wp-split-view/wp-split-view.html b/frontend/src/app/modules/work_packages/routing/wp-split-view/wp-split-view.html index ec9e9b05ea9..e93428f3401 100644 --- a/frontend/src/app/modules/work_packages/routing/wp-split-view/wp-split-view.html +++ b/frontend/src/app/modules/work_packages/routing/wp-split-view/wp-split-view.html @@ -10,10 +10,10 @@
    - - +
    diff --git a/frontend/src/global_styles/content/_collapsible_section.sass b/frontend/src/global_styles/content/_collapsible_section.sass index ea46caad68b..4193ded4bfb 100644 --- a/frontend/src/global_styles/content/_collapsible_section.sass +++ b/frontend/src/global_styles/content/_collapsible_section.sass @@ -13,6 +13,10 @@ .collapsible-section--toggle-link @include without-link-styling + background: none + border: none + width: 100% + text-align: left display: block cursor: pointer color: var(--body-font-color) diff --git a/frontend/src/global_styles/content/_in_place_editing.lsg b/frontend/src/global_styles/content/_in_place_editing.lsg index b1132c2a6f2..bc1d8a41dc6 100644 --- a/frontend/src/global_styles/content/_in_place_editing.lsg +++ b/frontend/src/global_styles/content/_in_place_editing.lsg @@ -17,201 +17,3 @@
    ``` - - -## In place editing: Attributes - -``` -
    -
    -
    -

    - Details -

    -
    -
    -
    -
    - Custom Field -
    -
    - -
    - - Editable text field - -
    -
    -
    -
    -
    -``` - -## In place editing: Single line of text - -### Read mode - -``` - - ``` - - -## In place editing: Multiple lines of text - -### Read mode - -``` -
    -
    -
    -
    -

    Description

    -
    -
    -
    - -
    -
    - -
    -

    - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. - Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. - Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim -

    -
    -
    -
    -
    -
    -
    -``` - -### Edit mode - -``` -
    - -
    -
    -

    - Description -

    -
    -
    - -
    - -
    - -
    -
    -
    -
    - - - -   - - - -   - - -   - - -   - - - - -
    - -
    - -
    - -
    -
    - -
    -
    -
    -
    -
    -
    - -``` diff --git a/frontend/src/global_styles/content/_work_packages.sass b/frontend/src/global_styles/content/_work_packages.sass index c0ce75e9b87..34b4dd6fcec 100644 --- a/frontend/src/global_styles/content/_work_packages.sass +++ b/frontend/src/global_styles/content/_work_packages.sass @@ -47,11 +47,10 @@ // WP single view styles @import work_packages/single_view/single_view @import work_packages/single_view/attachments -@import work_packages/single_view/inplace_esque_fields +@import work_packages/single_view/work_package_comment // WP fullscreen specific styles @import work_packages/fullscreen/fullscreen -@import work_packages/fullscreen/back_button // Tabs @import work_packages/tabs/activities diff --git a/frontend/src/global_styles/content/work_packages/fullscreen/_back_button.sass b/frontend/src/global_styles/content/work_packages/fullscreen/_back_button.sass deleted file mode 100644 index 9e47882f951..00000000000 --- a/frontend/src/global_styles/content/work_packages/fullscreen/_back_button.sass +++ /dev/null @@ -1,24 +0,0 @@ -.wp-show--back-button - min-width: 90px - height: 34px - a - padding: 0 - line-height: 32px - margin: 0 - width: 75px - height: 34px - - .button--icon:before - font-size: 1rem - line-height: 22px - - @media only screen and (max-width: 679px) - .router--work-packages-base & - // Move button in the current reverse order to front - position: absolute - top: 0 - left: 0 - z-index: 1 - - a - width: 100% diff --git a/frontend/src/global_styles/content/work_packages/inplace_editing/_textareas.sass b/frontend/src/global_styles/content/work_packages/inplace_editing/_textareas.sass index 177cb43b5d9..3c426ede7f7 100644 --- a/frontend/src/global_styles/content/work_packages/inplace_editing/_textareas.sass +++ b/frontend/src/global_styles/content/work_packages/inplace_editing/_textareas.sass @@ -55,11 +55,12 @@ text-align: center // Align controls via flex display: flex + justify-content: space-evenly + align-items: center float: right // Disabled submit styles when not applicable -.inplace-edit--control--save[disabled] a, -.inplace-edit--control--send[disabled] a +.inplace-edit--control[disabled] background-color: var(--inplace-edit--bg-color--disabled) color: var(--inplace-edit--color--disabled) cursor: not-allowed @@ -67,19 +68,19 @@ // A single save/cancel control .inplace-edit--control font-size: 0.9rem - flex: 1 - padding: 5px - a - // Center save/cancel links - width: 100% - line-height: 27px - border: 1px solid transparent - display: inline-block - color: var(--body-font-color) - text-decoration: none + width: 29px + height: 29px + background: none - &:hover, &:active - border-color: var(--inplace-edit--border-color) + // Center save/cancel links + line-height: 27px + border: 1px solid transparent + display: inline-block + color: var(--body-font-color) + text-decoration: none + + &:hover, &:active + border-color: var(--inplace-edit--border-color) .icon-context:before padding: 0 diff --git a/frontend/src/global_styles/content/work_packages/single_view/_inplace_esque_fields.sass b/frontend/src/global_styles/content/work_packages/single_view/_inplace_esque_fields.sass deleted file mode 100644 index 45a917b8c61..00000000000 --- a/frontend/src/global_styles/content/work_packages/single_view/_inplace_esque_fields.sass +++ /dev/null @@ -1,76 +0,0 @@ -// Add a border at all times to the inplace container -.inplace-editing--container - position: relative - -// need to specify the a explicitly as otherwise -// the default class will win -a.inplace-editing--trigger-link, -.inplace-editing--trigger-link - &:hover, - &:focus, - &.-focus - text-decoration: none - color: var(--body-font-color) - - &.-active - border-color: transparent - - .inplace-editing--container - border-color: var(--inplace-edit--border-color) - - .inplace-editing--trigger-icon - visibility: visible - -// Do not hover trigger-link when element is read-only -.-read-only - .inplace-editing--trigger-link:hover .inplace-editing--container - border-color: transparent - -// Explicit styles for input-esque trigger appearance -.work-packages--activity--add-comment, -.work-package--watchers-lookup - .inplace-editing--container - border: 1px solid #eee - -// Explicit styling for the comment and watcher container -.work-packages--activity--add-comment, -.work-package--watchers-lookup - margin: 20px 0 - - // Styles the comment trigger link similar to attachment - // but without icon and actual link - a.inplace-editing--trigger-link - color: var(--body-font-color) - font-style: italic - -// The trigger text left to the edit icon -.inplace-editing--trigger-text - width: calc(100% - 42px) - padding: 3px - line-height: 2 - display: inline-block - -// The edit icon to the right of the trigger text -.inplace-editing--trigger-icon - position: absolute - height: 100% - top: 0 - right: 0 - text-align: center - width: 32px - background: $gray-light - border-left: 1px solid var(--inplace-edit--border-color) - color: var(--body-font-color) - visibility: hidden - - i - position: relative - // Position the icon in the middle - top: calc(50% - 0.5rem) - - .icon-context:before - // HACK: overriding default padding here - padding-right: 0 - - &:hover - text-decoration: none diff --git a/frontend/src/global_styles/content/work_packages/single_view/_single_view.sass b/frontend/src/global_styles/content/work_packages/single_view/_single_view.sass index 30197b6abb0..c1ae97187aa 100644 --- a/frontend/src/global_styles/content/work_packages/single_view/_single_view.sass +++ b/frontend/src/global_styles/content/work_packages/single_view/_single_view.sass @@ -95,15 +95,6 @@ i vertical-align: -2px padding: 0 0 0 4px -.work-packages--details-close-icon span, -.work-packages--details-fullscreen-icon span - display: inline-block - padding-top: 2px - font-size: 0.9rem - - &:before - color: var(--body-font-color) - // -------------------- Attribute groups -------------------- // Special styling for project context area .attributes-group.-project-context diff --git a/frontend/src/global_styles/content/work_packages/single_view/_work_package_comment.sass b/frontend/src/global_styles/content/work_packages/single_view/_work_package_comment.sass new file mode 100644 index 00000000000..13a4e6ff9c2 --- /dev/null +++ b/frontend/src/global_styles/content/work_packages/single_view/_work_package_comment.sass @@ -0,0 +1,41 @@ +.work-package-comment + display: flex + align-items: center + width: 100% + color: var(--body-font-color) + padding: 0 + margin: 0 + background: none + border: 1px solid #eee + cursor: pointer + height: 42px + + + &:hover &, + &:focus & + border-color: var(--inplace-edit--border-color) + text-decoration: none + color: var(--body-font-color) + + &--icon + visibility: visible + + // The trigger text left to the edit icon + &--text + flex: 1 + padding: 3px + + // The edit icon to the right of the trigger text + &--icon + height: 100% + text-align: center + width: 32px + background: var(--gray-light) + border-left: 1px solid var(--inplace-edit--border-color) + color: var(--body-font-color) + visibility: hidden + // Align the icon centered + display: flex + align-items: center + justify-content: center + diff --git a/frontend/src/global_styles/fonts/_openproject_icon_font.sass b/frontend/src/global_styles/fonts/_openproject_icon_font.sass index 0ba94902fcc..d3014a93922 100644 --- a/frontend/src/global_styles/fonts/_openproject_icon_font.sass +++ b/frontend/src/global_styles/fonts/_openproject_icon_font.sass @@ -248,4 +248,4 @@ // Icon required for documents activity .icon-document - @extend .icon-notes + @extend .icon-notes \ No newline at end of file diff --git a/spec/features/support/components/attribute_help_text_modal.rb b/spec/features/support/components/attribute_help_text_modal.rb index 5155f57dbcb..d1426888898 100644 --- a/spec/features/support/components/attribute_help_text_modal.rb +++ b/spec/features/support/components/attribute_help_text_modal.rb @@ -52,7 +52,7 @@ module Components def open! SeleniumHubWaiter.wait - container.find(".help-text--for-#{help_text.attribute_name}").click + container.find("[data-qa-help-text-for='#{help_text.attribute_name}']").click expect(page).to have_selector('.attribute-help-text--modal h1', text: help_text.attribute_caption) end diff --git a/spec/features/work_packages/attribute_help_texts_spec.rb b/spec/features/work_packages/attribute_help_texts_spec.rb index 7987c3037c3..15002f8b1b2 100644 --- a/spec/features/work_packages/attribute_help_texts_spec.rb +++ b/spec/features/work_packages/attribute_help_texts_spec.rb @@ -52,7 +52,7 @@ describe 'Work package attribute help texts', type: :feature, js: true do shared_examples 'allows to view help texts' do it 'shows an indicator for whatever help text exists' do - expect(page).to have_selector('.work-package--single-view .help-text--for-status') + expect(page).to have_selector('.work-package--single-view [data-qa-help-text-for="status"]') # Open help text modal modal.open! diff --git a/spec/features/work_packages/details/relations/relations_spec.rb b/spec/features/work_packages/details/relations/relations_spec.rb index 9b85702bfa7..0c2d6e7a14d 100644 --- a/spec/features/work_packages/details/relations/relations_spec.rb +++ b/spec/features/work_packages/details/relations/relations_spec.rb @@ -242,11 +242,11 @@ describe 'Work package relations tab', js: true, selenium: true do textarea.set 'my description!' # Save description - created_row.find('.inplace-edit--control--save a').click + created_row.find('.inplace-edit--control--save').click loading_indicator_saveguard - # Wait for the relations table to be present + # Wait for the relations table to be presen sleep 2 expect(page).to have_selector('.wp-relations--subject-field') @@ -264,7 +264,7 @@ describe 'Work package relations tab', js: true, selenium: true do text: 'my description!').click # Cancel edition - created_row.find('.inplace-edit--control--cancel a').click + created_row.find('.inplace-edit--control--cancel').click created_row.find('.wp-relation--description-read-value', text: 'my description!').click diff --git a/spec/features/wysiwyg/user_mention_spec.rb b/spec/features/wysiwyg/user_mention_spec.rb index ff425d511cd..07267538e8d 100644 --- a/spec/features/wysiwyg/user_mention_spec.rb +++ b/spec/features/wysiwyg/user_mention_spec.rb @@ -78,14 +78,12 @@ describe 'Wysiwyg work package user mentions', expect(page) .to have_selector('a.mention', text: '@Foo Bar') - retry_block do - comment_field.submit_by_click if comment_field.active? + comment_field.submit_by_click if comment_field.active? - wp_page.expect_and_dismiss_notification message: "The comment was successfully added." + wp_page.expect_and_dismiss_notification message: "The comment was successfully added." - expect(page) - .to have_selector('a.user-mention', text: 'Foo Bar') - end + expect(page) + .to have_selector('a.user-mention', text: 'Foo Bar') # Mentioning a group works comment_field.activate! @@ -99,21 +97,19 @@ describe 'Wysiwyg work package user mentions', expect(page) .to have_selector('a.mention', text: '@Foogroup') - retry_block do - comment_field.submit_by_click if comment_field.active? + comment_field.submit_by_click if comment_field.active? - wp_page.expect_and_dismiss_notification message: "The comment was successfully added." + wp_page.expect_and_dismiss_notification message: "The comment was successfully added." - expect(page) - .to have_selector('a.user-mention', text: 'Foogroup') - end + expect(page) + .to have_selector('a.user-mention', text: 'Foogroup') # The mention is still displayed as such when reentering the comment field - find('#activity-1') + find('#activity-1 .op-user-activity') .hover within('#activity-1') do - click_link("Edit this comment") + click_button("Edit this comment") end expect(page) diff --git a/spec/support/edit_fields/edit_field.rb b/spec/support/edit_fields/edit_field.rb index ed5f6b727cf..ca5f6d20c57 100644 --- a/spec/support/edit_fields/edit_field.rb +++ b/spec/support/edit_fields/edit_field.rb @@ -125,7 +125,7 @@ class EditField end def submit_by_dashboard - field_container.find('.inplace-edit--control--save a', wait: 5).click + field_container.find('.inplace-edit--control--save', wait: 5).click end ## diff --git a/spec/support/edit_fields/text_editor_field.rb b/spec/support/edit_fields/text_editor_field.rb index 94e905367bf..176281ccada 100644 --- a/spec/support/edit_fields/text_editor_field.rb +++ b/spec/support/edit_fields/text_editor_field.rb @@ -42,7 +42,7 @@ class TextEditorField < EditField end def submit_by_click - target = field_container.find(control_link) + target = field_container.find(control_link, wait: 10) scroll_to_element(target) target.click end @@ -52,7 +52,7 @@ class TextEditorField < EditField end def cancel_by_click - target = field_container.find(control_link(:cancel)) + target = field_container.find(control_link(:cancel), wait: 10) scroll_to_element(target) target.click end @@ -64,6 +64,6 @@ class TextEditorField < EditField def control_link(action = :save) raise 'Invalid link' unless %i[save cancel].include?(action) - ".inplace-edit--control--#{action}" + ".inplace-edit--control--#{action}:not([disabled])" end end diff --git a/spec/support/pages/work_packages/abstract_work_package.rb b/spec/support/pages/work_packages/abstract_work_package.rb index c778ea4d382..9ee562b82b8 100644 --- a/spec/support/pages/work_packages/abstract_work_package.rb +++ b/spec/support/pages/work_packages/abstract_work_package.rb @@ -245,7 +245,7 @@ module Pages end def trigger_edit_comment - add_comment_container.find('.inplace-editing--trigger-link').click + add_comment_container.find('.work-package-comment').click end def update_comment(comment) @@ -255,7 +255,7 @@ module Pages def save_comment label = 'Comment: Save' - add_comment_container.find(:xpath, "//a[@title='#{label}']").click + add_comment_container.find(:xpath, "//button[@title='#{label}']").click end def save!