Skip to content

Commit afbf883

Browse files
committed
[#70420] Rework close, delete buttons as IconButtons
Fixes various eslint errors, replacing links and other non-focusable elements with `IconButton`. Introduces an initial port of Primer's `IconButton` to Angular, along with `octicon` directive to allow rendering icons by name.
1 parent f332d44 commit afbf883

16 files changed

+750
-20
lines changed

config/locales/js-en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ en:
225225
add_table: "Add table of related work packages"
226226
edit_query: "Edit query"
227227
new_group: "New group"
228+
delete_group: "Delete group"
229+
remove_attribute: "Remove from group"
228230
reset_to_defaults: "Reset to defaults"
229231

230232
working_days:

frontend/src/app/features/admin/types/attribute-group.component.html

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44
<op-group-edit-in-place [name]="group.name"
55
(onValueChange)="rename($event)"
66
class="group-name" />
7-
<span class="delete-group icon-small icon-close" (click)="deleteGroup.emit()"></span>
7+
<primer-icon-button
8+
icon="x"
9+
scheme="invisible"
10+
size="small"
11+
class="delete-group"
12+
tooltip-direction="w"
13+
[label]="text.delete_group"
14+
(clicked)="deleteGroup.emit()"
15+
/>
816
</div>
917
<div class="attributes" dragula="attributes" [(dragulaModel)]="group.attributes">
1018
@for (attribute of group.attributes; track attribute) {
@@ -20,7 +28,15 @@
2028
</span>
2129
}
2230
</span>
23-
<span class="delete-attribute icon-small icon-close" (click)="removeFromGroup(attribute)"></span>
31+
<primer-icon-button
32+
icon="x"
33+
scheme="invisible"
34+
size="small"
35+
class="delete-attribute"
36+
tooltip-direction="w"
37+
[label]="text.remove_attribute"
38+
(clicked)="removeFromGroup(attribute)"
39+
/>
2440
</div>
2541
}
2642
</div>

frontend/src/app/features/admin/types/attribute-group.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export class TypeFormAttributeGroupComponent {
1919

2020
text = {
2121
custom_field: this.I18n.t('js.admin.type_form.custom_field'),
22+
delete_group: this.I18n.t('js.admin.type_form.delete_group'),
23+
remove_attribute: this.I18n.t('js.admin.type_form.remove_attribute')
2224
};
2325

2426
constructor(private I18n:I18nService,

frontend/src/app/features/admin/types/query-group.component.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@
44
<op-group-edit-in-place [name]="group.name"
55
(onValueChange)="rename($event)"
66
class="group-name" />
7-
<span class="delete-group icon-small icon-close" (click)="deleteGroup.emit()"></span>
7+
<primer-icon-button
8+
icon="x"
9+
scheme="invisible"
10+
size="small"
11+
class="delete-group"
12+
tooltip-direction="w"
13+
[label]="text.delete_group"
14+
(clicked)="deleteGroup.emit()"
15+
/>
816
</div>
917
<div class="type-form-query">
1018
<span class="type-form-query-group--edit-button" (click)="editQuery.emit()">

frontend/src/app/features/admin/types/query-group.component.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { TypeGroup } from 'core-app/features/admin/types/type-form-configuration
1313
export class TypeFormQueryGroupComponent {
1414
text = {
1515
edit_query: this.I18n.t('js.admin.type_form.edit_query'),
16+
delete_group: this.I18n.t('js.admin.type_form.delete_group')
1617
};
1718

1819
@Input() public group:TypeGroup;

frontend/src/app/features/work-packages/components/filters/query-filters/query-filters.component.html

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
<fieldset id="filters" class="advanced-filters--container">
33
<legend [textContent]="text.selected_filter_list"></legend>
44
@if (showCloseFilter) {
5-
<a
6-
[attr.title]="text.close_form"
7-
class="advanced-filters--close icon-context icon-close"
8-
(click)="closeFilter()">
9-
</a>
5+
<primer-icon-button
6+
icon="x"
7+
scheme="invisible"
8+
class="advanced-filters--close"
9+
tooltip-direction="se"
10+
[label]="text.close_form"
11+
(clicked)="closeFilter()"
12+
/>
1013
}
1114
<ul class="advanced-filters--filters">
1215
<li id="filter_search"
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//-- copyright
2+
// OpenProject is an open source project management software.
3+
// Copyright (C) the OpenProject GmbH
4+
//
5+
// This program is free software; you can redistribute it and/or
6+
// modify it under the terms of the GNU General Public License version 3.
7+
//
8+
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
9+
// Copyright (C) 2006-2013 Jean-Philippe Lang
10+
// Copyright (C) 2010-2013 the ChiliProject Team
11+
//
12+
// This program is free software; you can redistribute it and/or
13+
// modify it under the terms of the GNU General Public License
14+
// as published by the Free Software Foundation; either version 2
15+
// of the License, or (at your option) any later version.
16+
//
17+
// This program is distributed in the hope that it will be useful,
18+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
// GNU General Public License for more details.
21+
//
22+
// You should have received a copy of the GNU General Public License
23+
// along with this program; if not, write to the Free Software
24+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25+
//
26+
// See COPYRIGHT and LICENSE files for more details.
27+
//++
28+
29+
import { booleanAttribute, Directive, input } from '@angular/core';
30+
31+
type ButtonType = 'button' | 'reset' | 'submit';
32+
33+
@Directive({})
34+
export abstract class AbstractBaseButtonDirective {
35+
readonly type = input<ButtonType>('button');
36+
37+
/**
38+
* Whether button is full-width with `display: block`
39+
*
40+
* @default false
41+
*/
42+
readonly block = input(false, { transform: booleanAttribute });
43+
44+
/**
45+
* Whether or not the button is disabled. If true, this option forces `tag` to `button`.
46+
*
47+
* @default false
48+
*/
49+
readonly disabled = input(false, { transform: booleanAttribute });
50+
51+
/**
52+
* Whether the button looks visually disabled, but can still accept all the same interactions as an enabled button.
53+
*
54+
* @default false
55+
*/
56+
readonly inactive = input(false, { transform: booleanAttribute });
57+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//-- copyright
2+
// OpenProject is an open source project management software.
3+
// Copyright (C) the OpenProject GmbH
4+
//
5+
// This program is free software; you can redistribute it and/or
6+
// modify it under the terms of the GNU General Public License version 3.
7+
//
8+
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
9+
// Copyright (C) 2006-2013 Jean-Philippe Lang
10+
// Copyright (C) 2010-2013 the ChiliProject Team
11+
//
12+
// This program is free software; you can redistribute it and/or
13+
// modify it under the terms of the GNU General Public License
14+
// as published by the Free Software Foundation; either version 2
15+
// of the License, or (at your option) any later version.
16+
//
17+
// This program is distributed in the hope that it will be useful,
18+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
// GNU General Public License for more details.
21+
//
22+
// You should have received a copy of the GNU General Public License
23+
// along with this program; if not, write to the Free Software
24+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25+
//
26+
// See COPYRIGHT and LICENSE files for more details.
27+
//++
28+
29+
/* eslint-disable @angular-eslint/directive-selector */
30+
31+
import { Directive } from '@angular/core';
32+
import { AbstractBaseButtonDirective } from './abstract-base-button.directive';
33+
34+
@Directive({
35+
selector: `
36+
button[primerBaseButton],
37+
a[primerBaseButton],
38+
summary[primerBaseButton],
39+
clipboard-copy[primerBaseButton]
40+
`,
41+
host: {
42+
'[class.btn-block]': 'block()',
43+
'[class.Button--inactive]': 'inactive()',
44+
'[disabled]': 'disabled()',
45+
'[attr.type]': 'type()',
46+
}
47+
})
48+
export class PrimerBaseButtonDirective extends AbstractBaseButtonDirective {
49+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//-- copyright
2+
// OpenProject is an open source project management software.
3+
// Copyright (C) the OpenProject GmbH
4+
//
5+
// This program is free software; you can redistribute it and/or
6+
// modify it under the terms of the GNU General Public License version 3.
7+
//
8+
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
9+
// Copyright (C) 2006-2013 Jean-Philippe Lang
10+
// Copyright (C) 2010-2013 the ChiliProject Team
11+
//
12+
// This program is free software; you can redistribute it and/or
13+
// modify it under the terms of the GNU General Public License
14+
// as published by the Free Software Foundation; either version 2
15+
// of the License, or (at your option) any later version.
16+
//
17+
// This program is distributed in the hope that it will be useful,
18+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
// GNU General Public License for more details.
21+
//
22+
// You should have received a copy of the GNU General Public License
23+
// along with this program; if not, write to the Free Software
24+
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25+
//
26+
// See COPYRIGHT and LICENSE files for more details.
27+
//++
28+
29+
import { starIconData, SVGData, xIconData } from '@openproject/octicons-angular';
30+
31+
export const ICON_MAP:Record<string, SVGData> = {
32+
x: xIconData,
33+
star: starIconData,
34+
// TODO add more icons
35+
};

0 commit comments

Comments
 (0)