From 65d809dd8d81daecdaa389f329047ab899bdccad Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Mon, 5 May 2025 17:28:57 +0200 Subject: [PATCH] Basic models for Fizzy do and searches working with them --- app/controllers/commands_controller.rb | 25 +++++ .../controllers/commands_controller.js | 8 ++ app/models/command.rb | 20 ++++ app/models/command/go_to_card.rb | 24 +++++ app/models/command/parser.rb | 15 +++ app/models/command/result/redirection.rb | 1 + app/models/command/search.rb | 15 +++ app/models/user.rb | 1 + app/views/layouts/application.html.erb | 2 +- app/views/my/commands/_input.html.erb | 26 +++++ app/views/terminals/show.html.erb | 6 +- config/routes.rb | 2 + db/migrate/20250505123008_create_commands.rb | 10 ++ db/schema.rb | 12 ++- db/schema_cache.yml | 94 +++++++++++-------- 15 files changed, 217 insertions(+), 44 deletions(-) create mode 100644 app/controllers/commands_controller.rb create mode 100644 app/javascript/controllers/commands_controller.js create mode 100644 app/models/command.rb create mode 100644 app/models/command/go_to_card.rb create mode 100644 app/models/command/parser.rb create mode 100644 app/models/command/result/redirection.rb create mode 100644 app/models/command/search.rb create mode 100644 app/views/my/commands/_input.html.erb create mode 100644 db/migrate/20250505123008_create_commands.rb diff --git a/app/controllers/commands_controller.rb b/app/controllers/commands_controller.rb new file mode 100644 index 000000000..143ff514d --- /dev/null +++ b/app/controllers/commands_controller.rb @@ -0,0 +1,25 @@ +class CommandsController < ApplicationController + def create + command = parse_command(params[:command]) + + if command + result = command.execute + + case result + when Command::Result::Redirection + redirect_to url_for(result.url) + else + redirect_back_or_to root_path + end + else + raise "Pending to handle invalid commands" + end + end + + private + def parse_command(string) + Command::Parser.new(Current.user).parse(string).tap do |command| + Current.user.commands << command if command + end + end +end diff --git a/app/javascript/controllers/commands_controller.js b/app/javascript/controllers/commands_controller.js new file mode 100644 index 000000000..98eaa7598 --- /dev/null +++ b/app/javascript/controllers/commands_controller.js @@ -0,0 +1,8 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "input" ] + + // Actions + +} diff --git a/app/models/command.rb b/app/models/command.rb new file mode 100644 index 000000000..fb8cfbd2c --- /dev/null +++ b/app/models/command.rb @@ -0,0 +1,20 @@ +class Command < ApplicationRecord + include Rails.application.routes.url_helpers + + belongs_to :user + + def execute + end + + def undo + end + + def can_undo? + false + end + + private + def redirect_to(...) + Command::Result::Redirection.new(...) + end +end diff --git a/app/models/command/go_to_card.rb b/app/models/command/go_to_card.rb new file mode 100644 index 000000000..b3e3122c5 --- /dev/null +++ b/app/models/command/go_to_card.rb @@ -0,0 +1,24 @@ +class Command::GoToCard < Command + store_accessor :data, :card_id + + def card=(card) + self.card_id = card.id + end + + def execute + redirect_to card + end + + def description + "Search '#{query}" + end + + def to_command + query + end + + private + def card + user.accessible_cards.find(card_id) + end +end diff --git a/app/models/command/parser.rb b/app/models/command/parser.rb new file mode 100644 index 000000000..1f173c0cb --- /dev/null +++ b/app/models/command/parser.rb @@ -0,0 +1,15 @@ +class Command::Parser + attr_reader :user + + def initialize(user) + @user = user + end + + def parse(string) + if card = user.accessible_cards.find_by_id(string) + Command::GoToCard.new(card: card) + else + Command::Search.new(query: string) + end + end +end diff --git a/app/models/command/result/redirection.rb b/app/models/command/result/redirection.rb new file mode 100644 index 000000000..3fd5b9b8d --- /dev/null +++ b/app/models/command/result/redirection.rb @@ -0,0 +1 @@ +Command::Result::Redirection = Struct.new(:url) diff --git a/app/models/command/search.rb b/app/models/command/search.rb new file mode 100644 index 000000000..c8e383950 --- /dev/null +++ b/app/models/command/search.rb @@ -0,0 +1,15 @@ +class Command::Search < Command + store_accessor :data, :query + + def execute + redirect_to cards_path("terms[]": query) + end + + def description + "Search '#{query}" + end + + def to_command + query + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 370aae05c..d68ccff46 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -15,6 +15,7 @@ class User < ApplicationRecord has_many :closures, dependent: :nullify has_many :pins, dependent: :destroy has_many :pinned_cards, through: :pins, source: :card + has_many :commands, dependent: :destroy normalizes :email_address, with: ->(value) { value.strip.downcase } diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index fd857fafe..804999cdb 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -50,7 +50,7 @@ <% end %> diff --git a/app/views/my/commands/_input.html.erb b/app/views/my/commands/_input.html.erb new file mode 100644 index 000000000..ae80a5402 --- /dev/null +++ b/app/views/my/commands/_input.html.erb @@ -0,0 +1,26 @@ +<%= tag.div class: "terminal full-width flex flex-column gap justify-end", data: { + controller: "toggle-class commands", + toggle_class_toggle_class: "terminal--open" } do %> + + <% # Should move to frame %> + <%= render partial: "terminals/event", collection: Current.user.accessible_events.chronologically.reverse_order.limit(20) %> + + + <%= form_tag commands_path, + class: "flex align-center gap-half", + data: { controller: "form" } do %> + + + <%= text_field_tag "command", nil, + autocomplete: "off", + autocorrect: "off", + autocapitalize: "off", + class: "terminal__input input fill-transparent unpad", + data: { + commands_target: "input", + action: "keydown.up->toggle-class#add:prevent keydown.down->toggle-class#remove:prevent" + }, + placeholder: "Search or type commands…" %> + <% end %> +<% end %> + diff --git a/app/views/terminals/show.html.erb b/app/views/terminals/show.html.erb index 843d79039..aa2b19706 100644 --- a/app/views/terminals/show.html.erb +++ b/app/views/terminals/show.html.erb @@ -1,9 +1,9 @@ <%= turbo_frame_tag "terminal" do %>
- <%= render partial: "event", collection: @events %> + <%= render partial: "event", collection: @events %> - + <%= turbo_frame_tag "terminal_form" do %> <%= link_to edit_terminal_path, class: "terminal__link flex align-center gap-half min-width", data: { action: "keydown.meta+shift+p@document->hotkey#click", controller: "hotkey" } do %> Fizzy do > @@ -11,4 +11,4 @@ <% end %> <% end %>
-<% end %> \ No newline at end of file +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 762985595..733128e1e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -89,6 +89,8 @@ Rails.application.routes.draw do end end + resources :commands + namespace :my do resources :pins end diff --git a/db/migrate/20250505123008_create_commands.rb b/db/migrate/20250505123008_create_commands.rb new file mode 100644 index 000000000..61b3868eb --- /dev/null +++ b/db/migrate/20250505123008_create_commands.rb @@ -0,0 +1,10 @@ +class CreateCommands < ActiveRecord::Migration[8.1] + def change + create_table :commands do |t| + t.references :user, null: false, foreign_key: true, index: true + t.json :data, default: {} + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index fd3176781..f64ff1720 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2025_04_29_162506) do +ActiveRecord::Schema[8.1].define(version: 2025_05_05_123008) do create_table "accesses", force: :cascade do |t| t.integer "collection_id", null: false t.datetime "created_at", null: false @@ -159,6 +159,14 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_29_162506) do t.index ["filter_id"], name: "index_collections_filters_on_filter_id" end + create_table "commands", force: :cascade do |t| + t.datetime "created_at", null: false + t.json "data", default: {} + t.datetime "updated_at", null: false + t.integer "user_id", null: false + t.index ["user_id"], name: "index_commands_on_user_id" + end + create_table "comments", force: :cascade do |t| t.integer "card_id", null: false t.datetime "created_at", null: false @@ -280,7 +288,6 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_29_162506) do t.datetime "created_at", null: false t.string "title" t.datetime "updated_at", null: false - t.index ["title"], name: "index_tags_on_account_id_and_title", unique: true end create_table "users", force: :cascade do |t| @@ -327,6 +334,7 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_29_162506) do add_foreign_key "closures", "cards" add_foreign_key "closures", "users" add_foreign_key "collections", "workflows" + add_foreign_key "commands", "users" add_foreign_key "comments", "cards" add_foreign_key "events", "collections" add_foreign_key "mentions", "users", column: "mentionee_id" diff --git a/db/schema_cache.yml b/db/schema_cache.yml index c196953f7..86315984a 100644 --- a/db/schema_cache.yml +++ b/db/schema_cache.yml @@ -80,7 +80,7 @@ columns: default_function: collation: comment: - - &28 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column + - &24 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: user_id cast_type: *1 @@ -532,6 +532,29 @@ columns: collections_filters: - *22 - *18 + commands: + - *5 + - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column + auto_increment: + name: data + cast_type: &25 !ruby/object:ActiveRecord::Type::Json + precision: + scale: + limit: + sql_type_metadata: &26 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata + sql_type: json + type: :json + limit: + precision: + scale: + 'null': true + default: "{}" + default_function: + collation: + comment: + - *6 + - *9 + - *24 comments: - *21 - *5 @@ -579,16 +602,8 @@ columns: - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: particulars - cast_type: &24 !ruby/object:ActiveRecord::Type::Json - precision: - scale: - limit: - sql_type_metadata: &25 !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata - sql_type: json - type: :json - limit: - precision: - scale: + cast_type: *25 + sql_type_metadata: *26 'null': true default: "{}" default_function: @@ -601,8 +616,8 @@ columns: - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: fields - cast_type: *24 - sql_type_metadata: *25 + cast_type: *25 + sql_type_metadata: *26 'null': false default: "{}" default_function: @@ -667,7 +682,7 @@ columns: default_function: collation: comment: - - &26 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column + - &27 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: source_id cast_type: *1 @@ -677,7 +692,7 @@ columns: default_function: collation: comment: - - &27 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column + - &28 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: source_type cast_type: *7 @@ -711,16 +726,16 @@ columns: default_function: collation: comment: - - *26 - *27 - - *9 - *28 + - *9 + - *24 pins: - *21 - *5 - *6 - *9 - - *28 + - *24 reactions: - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: @@ -800,7 +815,7 @@ columns: default_function: collation: comment: - - *28 + - *24 taggings: - *21 - *5 @@ -862,7 +877,7 @@ columns: - *5 - *6 - *9 - - *28 + - *24 - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column auto_increment: name: watching @@ -921,6 +936,7 @@ primary_keys: closures: id collections: id collections_filters: + commands: id comments: id creators_filters: events: id @@ -957,6 +973,7 @@ data_sources: closures: true collections: true collections_filters: true + commands: true comments: true creators_filters: true events: true @@ -1450,6 +1467,23 @@ indexes: nulls_not_distinct: comment: valid: true + commands: + - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition + table: commands + name: index_commands_on_user_id + unique: false + columns: + - user_id + lengths: {} + orders: {} + opclasses: {} + where: + type: + using: + include: + nulls_not_distinct: + comment: + valid: true comments: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: comments @@ -1905,23 +1939,7 @@ indexes: nulls_not_distinct: comment: valid: true - tags: - - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition - table: tags - name: index_tags_on_account_id_and_title - unique: true - columns: - - title - lengths: {} - orders: {} - opclasses: {} - where: - type: - using: - include: - nulls_not_distinct: - comment: - valid: true + tags: [] users: - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition table: users @@ -2006,4 +2024,4 @@ indexes: comment: valid: true workflows: [] -version: 20250429162506 +version: 20250505123008