Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Pattern input field #17472

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/components/_index.sass
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@
@import "work_package_relations_tab/index_component"
@import "users/hover_card_component"
@import "enterprise_edition/banner_component"
@import "work_packages/types/pattern_autocompleter"
119 changes: 119 additions & 0 deletions app/components/work_packages/types/pattern_autocompleter.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<%#-- copyright
OpenProject is an open source project management software.
Copyright (C) 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 COPYRIGHT and LICENSE files for more details.

++#%>

<%=
content_tag(
:div,
class: "pattern-autocompleter",
"data-controller": "pattern-autocompleter",
"data-pattern-autocompleter-pattern-initial-value": @value
) do
%>
<%=
@input.builder.hidden_field(
name,
value: @value,
data: {
"pattern-autocompleter-target": "formInput"
}
)
%>

<template data-pattern-autocompleter-target="tokenTemplate">
<%=
render(
Primer::Beta::Label.new(
contenteditable: false,
tag: :span, display: :inline, scheme: :accent,
"data-role": :token
)
) do
%>
<%= content_tag(:span, style: "cursor: default;", "data-role": "token-text") { "__VALUE__" } %>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not use inline styles. Either use system_arguments or if the style is not supported, add a class and write the styles in the CSS file.

<%=
render(
Primer::Beta::Octicon.new(
icon: :x, size: :xsmall, style: "cursor: pointer;margin: 0.2em;",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, please do not use inline styles. Further, 0.2 is somehow a magic number, that does not even align the cross to the center:
Bildschirmfoto 2025-01-15 um 07 56 45

Please try to resolve that with CSS alignment mechanism (e.g. vertica-align or a flex)

"data-action": "click->pattern-autocompleter#remove_token"
)
)
%>
<% end %>
</template>

<%= content_tag(:div, style: "position: relative;") do %>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<%= content_tag(:div, style: "position: relative;") do %>
<%= render(Primer::BaseComponent.new(tag: :div, position: :relative)) do %>

<%=
render(
Primer::Beta::Octicon.new(
icon: "triangle-down",
size: :small,
style: "cursor: pointer;position: absolute;right: 1em;top: 0.5em;",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Position absolute has some drawbacks in this case. You are enforcing it to lay at that specific place no matter what the content of the input is. Thus the content and the arrow can overlap:

Bildschirmfoto 2025-01-15 um 08 18 12

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see that arrow down at all until now 🙈

Devils advocate: Do we need this arrow at all? It makes the component look like a select, when it is mostly like a text input. E.g. we'd also not show an arrow down in a text input that allows autocompleting emojis (which I think is a good analogy for what we are doing here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The arrow allows for a mouse only interaction of adding tokens so I think it might be necessary. 🤔

"data-action": "click->pattern-autocompleter#suggestions_toggle"
)
)
%>
<%=
render(
Primer::Box.new(
contenteditable: true,
border: true, border_radius: 2, p: 1,
style: "white-space: pre-wrap;",
"data-pattern-autocompleter-target": "content",
data: {
action: "keydown->pattern-autocompleter#input_keydown
input->pattern-autocompleter#input_change
mouseup->pattern-autocompleter#input_mouseup
blur->pattern-autocompleter#input_blur"
}
)
)
%>
<% end %>
<%= render(Primer::Box.new(box_shadow: :medium, border_radius: 2)) do %>
<%=
render(
Primer::Alpha::ActionList.new(
role: :list,
hidden: true,
show_dividers: false,
"data-pattern-autocompleter-target": "suggestions"
)
) do |component|
@suggestions.each_key do |key|
component.with_divider_content(key.to_s.humanize)
entries = @suggestions[key]
entries.each do |prop, label|
component.with_item(label:, data: select_item_action.merge({ value: prop }))
end
component.with_divider
end
end
%>
<% end %>
<% end %>
51 changes: 51 additions & 0 deletions app/components/work_packages/types/pattern_autocompleter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2024 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 COPYRIGHT and LICENSE files for more details.
# ++

module WorkPackages
module Types
class PatternAutocompleter < Primer::Forms::BaseComponent
delegate :name, to: :@input

def initialize(input:, value:, suggestions:)
super()
@input = input
@value = value
@suggestions = suggestions
end

def select_item_action
{
action: "click->pattern-autocompleter#suggestions_select",
Copy link
Contributor

@NobodysNightmare NobodysNightmare Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just spotted this one and noticed that I didn't try using the mouse to select an autocomplete entry yet.

For me it doesn't work to click on an autoselect entry. The pop-up closes, but nothing gets selected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New learning: Selecting with the mouse works after opening the suggestion list via the arrow down button, but not when using the mouse after starting autocompletion via typing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I shall investigate. Maybe the focus group solution suggested above fixes all things and I can move on with life 👀

role: "suggestion-item"
}
end
end
end
end
5 changes: 5 additions & 0 deletions app/components/work_packages/types/pattern_autocompleter.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.pattern-autocompleter
.selected
color: var(--list-item-hover--color)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the ActionList component, they use --fgColor-default for hovered elements. As we try to mimic that style, I'd suggest that we use the same here.

background-color: var(--control-transparent-bgColor-hover)

6 changes: 3 additions & 3 deletions app/forms/work_packages/types/subject_configuration_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ def has_pattern?(type)
end

subject_form.group(data: { "admin--subject-configuration-target": "patternInput" }) do |toggleable_group|
toggleable_group.text_field(
toggleable_group.pattern_autocompleter(
name: :subject_pattern,
value: subject_pattern,
suggestions: ::Types::Patterns::TokenPropertyMapper.new.tokens_for_type(model),
label: I18n.t("types.edit.subject_configuration.pattern.label"),
caption: I18n.t("types.edit.subject_configuration.pattern.caption"),
required: true,
input_width: :large
required: true
)
end

Expand Down
Loading
Loading