From cae01b777e7b7cb77930396f85bed98bfe7ea6ec Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Tue, 1 Jul 2025 14:58:24 +0200 Subject: [PATCH] Add prompt for tags too --- .../prompts/collections/users_controller.rb | 2 +- app/controllers/prompts/tags_controller.rb | 9 +++++++++ app/controllers/prompts/users_controller.rb | 2 +- app/helpers/rich_text_helper.rb | 4 ++++ app/models/command/ai/translator.rb | 3 ++- app/models/command/parser.rb | 13 +++++++------ app/models/command/parser/context.rb | 12 +++++++++--- app/models/tag.rb | 7 ++++++- app/views/commands/_form.html.erb | 18 +++++++++++++++--- app/views/prompts/tags/_tag.html.erb | 8 ++++++++ app/views/prompts/tags/index.html.erb | 1 + config/routes.rb | 1 + 12 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 app/controllers/prompts/tags_controller.rb create mode 100644 app/views/prompts/tags/_tag.html.erb create mode 100644 app/views/prompts/tags/index.html.erb diff --git a/app/controllers/prompts/collections/users_controller.rb b/app/controllers/prompts/collections/users_controller.rb index 1802f8fd1..19edbbd5d 100644 --- a/app/controllers/prompts/collections/users_controller.rb +++ b/app/controllers/prompts/collections/users_controller.rb @@ -2,7 +2,7 @@ class Prompts::Collections::UsersController < ApplicationController include CollectionScoped def index - @users = @collection.users + @users = @collection.users.alphabetically if stale? etag: @users render layout: false diff --git a/app/controllers/prompts/tags_controller.rb b/app/controllers/prompts/tags_controller.rb new file mode 100644 index 000000000..5a90b23fb --- /dev/null +++ b/app/controllers/prompts/tags_controller.rb @@ -0,0 +1,9 @@ +class Prompts::TagsController < ApplicationController + def index + @tags = Tag.all.alphabetically + + if stale? etag: @tags + render layout: false + end + end +end diff --git a/app/controllers/prompts/users_controller.rb b/app/controllers/prompts/users_controller.rb index 4fbb605e9..1069c3841 100644 --- a/app/controllers/prompts/users_controller.rb +++ b/app/controllers/prompts/users_controller.rb @@ -1,6 +1,6 @@ class Prompts::UsersController < ApplicationController def index - @users = User.all + @users = User.all.alphabetically if stale? etag: @users render layout: false diff --git a/app/helpers/rich_text_helper.rb b/app/helpers/rich_text_helper.rb index 273ae2888..8cd4cf36c 100644 --- a/app/helpers/rich_text_helper.rb +++ b/app/helpers/rich_text_helper.rb @@ -7,6 +7,10 @@ module RichTextHelper content_tag "lexical-prompt", "", trigger: "@", src: prompts_users_path, name: "mention" end + def tags_prompt + content_tag "lexical-prompt", "", trigger: "#", src: prompts_tags_path, name: "tag" + end + def cards_prompt content_tag "lexical-prompt", "", trigger: "#", src: prompts_cards_path, name: "card", "insert-editable-text": true, "remote-filtering": true end diff --git a/app/models/command/ai/translator.rb b/app/models/command/ai/translator.rb index 914e7e95a..324bd982a 100644 --- a/app/models/command/ai/translator.rb +++ b/app/models/command/ai/translator.rb @@ -146,7 +146,8 @@ class Command::Ai::Translator * ❗ Once you produce a valid context **or** command list, do not add a fallback /search. ---------------------- RESOLVE COMMAND ARGUMENTS ---------------------- - * A person can be express by its name or via a global ID URL like gid://fizzy/User/773524000?tenant=37signals. + * A person can be expressed by its name or via a global ID URL like gid://fizzy/User/1234?tenant=37signals. + * A tag can be expressed by its text or via a global ID URL like gid://fizzy/Tag/5678?tenant=37signals. -------------------- COMMAND INTERPRETATION RULES -------------------- * /user → open that person’s profile or activity feed. diff --git a/app/models/command/parser.rb b/app/models/command/parser.rb index dfd24bb72..93445d717 100644 --- a/app/models/command/parser.rb +++ b/app/models/command/parser.rb @@ -24,11 +24,12 @@ class Command::Parser ActionText::Content.new(string).to_plain_text end - private def parse_command(string) rich_text_command = as_plain_text_with_attachable_references(string) plain_text_command = as_plain_text(string) + Rails.logger.info "COMMANDS: #{rich_text_command} AND #{plain_text_command}" + parse_plain_text_command(plain_text_command) || parse_rich_text_command(rich_text_command) end @@ -36,10 +37,10 @@ class Command::Parser command_name, *_ = string.strip.split(" ") case command_name - when /^#/ - Command::FilterByTag.new(tag_title: tag_title_from(string), params: filter.as_params) - when /^@/ - Command::GoToUser.new(user_id: context.find_user(command_name)&.id) + when /^#/ + Command::FilterByTag.new(tag_title: tag_title_from(string), params: filter.as_params) + when /^@/ + Command::GoToUser.new(user_id: context.find_user(command_name)&.id) end end @@ -88,7 +89,7 @@ class Command::Parser end def tag_title_from(string) - string.gsub(/^#/, "") + context.find_tag(string)&.title || string.gsub(/^#/, "") end def parse_free_string(string) diff --git a/app/models/command/parser/context.rb b/app/models/command/parser/context.rb index 6c2c93d5a..1908f1db4 100644 --- a/app/models/command/parser/context.rb +++ b/app/models/command/parser/context.rb @@ -29,11 +29,12 @@ class Command::Parser::Context end def find_user(string) + string = string.delete_prefix("@") + if string.starts_with?("gid://") User.find_by_id(GlobalID::Locator.locate(string).id) else - string_without_at = string.delete_prefix("@") - User.all.find { |user| user.mentionable_handles.include?(string_without_at.downcase) } + User.all.find { |user| user.mentionable_handles.include?(string.downcase) } end end @@ -44,7 +45,12 @@ class Command::Parser::Context end def find_tag(string) - Tag.find_by_title(string) + string = string.delete_prefix("#") + if string.starts_with?("gid://") + Tag.find_by_id(GlobalID::Locator.locate(string).id) + else + Tag.find_by_title(string) + end end def find_collection(string) diff --git a/app/models/tag.rb b/app/models/tag.rb index ce981f4ab..f1836515f 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -1,5 +1,5 @@ class Tag < ApplicationRecord - include Filterable + include ActionText::Attachable, Filterable has_many :taggings, dependent: :destroy has_many :cards, through: :taggings @@ -13,4 +13,9 @@ class Tag < ApplicationRecord def hashtag "#" + title end + + # TODO: Move to attachable along with the concern + def attachable_plain_text_representation(...) + "##{title}" + end end diff --git a/app/views/commands/_form.html.erb b/app/views/commands/_form.html.erb index 977e76419..7997dfcd7 100644 --- a/app/views/commands/_form.html.erb +++ b/app/views/commands/_form.html.erb @@ -4,7 +4,19 @@ data: { controller: "form", terminal_target: "form", - action: "turbo:submit-start->terminal#commandSubmitted turbo:submit-end->terminal#focus keydown.meta+k@document->terminal#focus:prevent keydown.ctrl+k@document->terminal#focus:prevent keydown.enter->terminal#executeCommand keydown.esc->terminal#hideMenus turbo:submit-end->terminal#handleCommandResponse" + action: " + keydown.enter->terminal#submitCommand + keydown.up->toggle-class#add:prevent + keydown.up->navigable-list#selectCurrentOrReset:stop + terminal#hideError + turbo:submit-start->terminal#commandSubmitted + turbo:submit-end->terminal#focus + keydown.meta+k@document->terminal#focus:prevent + keydown.ctrl+k@document->terminal#focus:prevent + keydown.enter->terminal#executeCommand + keydown.esc->terminal#hideMenus + turbo:submit-end->terminal#handleCommandResponse + " } do %> @@ -13,12 +25,12 @@ class: "terminal__input input fill-transparent unpad", "single-line": true, data: { - terminal_target: "input", - action: "keydown.enter->terminal#submitCommand keydown.up->toggle-class#add:prevent keydown.up->navigable-list#selectCurrentOrReset:stop terminal#hideError" + terminal_target: "input" }, placeholder: platform.desktop? ? "Press #{ hotkey_label(["ctrl", "K"]) } to search or type commands…" : "Search or type commands…", spellcheck: "false" do %> <%= global_mentions_prompt %> + <%= tags_prompt %> <% end %> <%= hidden_field_tag "confirmed", nil, data: { terminal_target: "confirmation" } %> diff --git a/app/views/prompts/tags/_tag.html.erb b/app/views/prompts/tags/_tag.html.erb new file mode 100644 index 000000000..904484f5d --- /dev/null +++ b/app/views/prompts/tags/_tag.html.erb @@ -0,0 +1,8 @@ + + + + diff --git a/app/views/prompts/tags/index.html.erb b/app/views/prompts/tags/index.html.erb new file mode 100644 index 000000000..7ff9bbb1f --- /dev/null +++ b/app/views/prompts/tags/index.html.erb @@ -0,0 +1 @@ +<%= render partial: "prompts/tags/tag", collection: @tags %> diff --git a/config/routes.rb b/config/routes.rb index 1c57cab10..4026c9c25 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -117,6 +117,7 @@ Rails.application.routes.draw do namespace :prompts do resources :cards resources :users + resources :tags resources :collections do scope module: :collections do