Remove Fizzy Do command logic

This commit is contained in:
Stanko K.R.
2025-08-18 15:51:16 +02:00
parent 4596c5364d
commit 89af9066d3
14 changed files with 0 additions and 383 deletions
-34
View File
@@ -1,34 +0,0 @@
class CommandsController < ApplicationController
def create
command = parse_command(params[:command])
result = command.execute
respond_with_execution_result(result)
end
private
def parse_command(string)
command_parser.parse(string)
end
def command_parser
@command_parser ||= Command::Parser.new(user: Current.user, script_name: request.script_name)
end
def respond_with_execution_result(result)
# This saves unnecessary back and forth between server and client (e.g: to redirect)-
result = result.is_a?(Array) && result.one? ? result.first : result
case result
when Command::Result::Redirection
redirect_to result.url
when Command::Result::ShowModal
respond_with_turbo_frame_modal(result.turbo_frame, result.url)
else
redirect_back_or_to root_path
end
end
def respond_with_turbo_frame_modal(turbo_frame, url)
render json: { turbo_frame: turbo_frame, url: url }, status: :accepted
end
end
@@ -1,91 +0,0 @@
import { Controller } from "@hotwired/stimulus"
import { HttpStatus } from "helpers/http_helpers"
import { isMultiLineString } from "helpers/text_helpers";
import { marked } from "marked"
import { nextFrame } from "helpers/timing_helpers";
export default class extends Controller {
static targets = [ "input", "form", "modalTurboFrame" ]
static classes = [ "error", "busy" ]
static outlets = [ "dialog" ]
// Actions
async focus() {
await nextFrame()
this.inputTarget.focus()
this.inputTarget.selection.placeCursorAtTheEnd()
}
executeCommand(event) {
if (!this.inputTarget.value.trim()) {
event.preventDefault()
}
}
submitCommand({ target }) {
this.#submitCommand()
}
handleCommandResponse(event) {
const response = event.detail.fetchResponse?.response
if (event.detail.success) {
this.#handleSuccessResponse(response)
} else if (response) {
this.#handleErrorResponse(response)
}
}
hideError() {
this.element.classList.remove(this.errorClass)
}
commandSubmitted() {
this.element.classList.add(this.busyClass)
}
#reset(inputValue = "") {
this.inputTarget.value = inputValue
this.element.classList.remove(this.errorClass)
this.element.classList.remove(this.busyClass)
}
#handleSuccessResponse(response) {
if (response.headers.get("Content-Type")?.includes("application/json")) {
response.json().then((responseJson) => {
this.#handleJsonResponse(responseJson)
})
}
this.#reset()
}
async #handleErrorResponse(response) {
this.element.classList.add(this.errorClass)
}
#handleJsonResponse(responseJson) {
const { redirect_to, turbo_frame, url } = responseJson
if (redirect_to) {
Turbo.visit(redirect_to)
}
if (turbo_frame && url) {
this.#showTurboFrameModal(turbo_frame, url)
}
}
#submitCommand() {
this.formTarget.requestSubmit()
}
#showTurboFrameModal(name, url) {
this.inputTarget.blur()
this.modalTurboFrameTarget.id = name
this.modalTurboFrameTarget.src = url
this.dialogOutlet.open()
}
}
-12
View File
@@ -1,12 +0,0 @@
class Command
include Rails.application.routes.url_helpers
def execute
raise NotImplementedError
end
private
def redirect_to(...)
Command::Result::Redirection.new(...)
end
end
-14
View File
@@ -1,14 +0,0 @@
class Command::Ask < Command
attr_reader :question
def initialize(question)
@question = question
end
def execute
conversation = Conversation.create_or_find_by(user: Current.user)
conversation.ask(question) if question.present?
Command::Result::ShowModal.new(turbo_frame: "conversation", url: conversation_path)
end
end
-11
View File
@@ -1,11 +0,0 @@
class Command::GoToCard < Command
attr_reader :card
def initialize(card)
@card = card
end
def execute
redirect_to card
end
end
-51
View File
@@ -1,51 +0,0 @@
class Command::Parser
attr_reader :user, :script_name
def initialize(user: user, script_name:)
@user = user
@script_name = script_name
end
def parse(string)
parse_command(string).tap do |command|
command.default_url_options[:script_name] = script_name
end
end
private
def parse_command(string)
parse_rich_text_command as_plain_text_with_attachable_references(string)
end
def as_plain_text_with_attachable_references(string)
ActionText::Content.new(string).render_attachments(&:to_gid).fragment.to_plain_text
end
def parse_rich_text_command(string)
command_name, *command_arguments = string.strip.split(" ")
combined_arguments = command_arguments.join(" ")
case command_name
when "/ask"
Command::Ask.new(combined_arguments)
else
parse_free_string(string)
end
end
def parse_free_string(string)
if card = single_card_from(string)
Command::GoToCard.new(card)
else
parse_with_fallback(string)
end
end
def single_card_from(string)
user.accessible_cards.find_by_id(string)
end
def parse_with_fallback(string)
Command::Search.new(string)
end
end
-11
View File
@@ -1,11 +0,0 @@
class Command::Result::Redirection
attr_reader :url
def initialize(url)
@url = url
end
def as_json
{ redirect_to: url }
end
end
-12
View File
@@ -1,12 +0,0 @@
class Command::Result::ShowModal
attr_reader :url, :turbo_frame
def initialize(url:, turbo_frame:)
@url = url
@turbo_frame = turbo_frame
end
def as_json
{ turbo_frame: turbo_frame, url: url }
end
end
-12
View File
@@ -1,12 +0,0 @@
class Command::Search < Command
attr_reader :terms
def initialize(terms)
@terms = terms
end
def execute
redirect_to search_path(q: terms)
end
end
-30
View File
@@ -1,30 +0,0 @@
<%= form_tag commands_path,
id: "commands_form",
class: [ "flex align-center gap-half" ],
data: {
controller: "form",
terminal_target: "form",
action: "
keydown.enter->terminal#submitCommand
turbo:submit-start->terminal#commandSubmitted
turbo:submit-end->terminal#focus
keydown.meta+k@document->terminal#focus:prevent
keydown.ctrl+k@document->terminal#focus:prevent
turbo:submit-end->terminal#handleCommandResponse
"
} do %>
<%= rich_textarea_tag "command", nil,
toolbar: false,
class: "terminal__input input hide-focus-ring fill-transparent unpad",
"single-line": true,
id: "command",
attachments: false,
data: {
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 %>
<% end %>
-37
View File
@@ -1,37 +0,0 @@
<section class="terminal__help shadow" aria-labelledby="help-menu-title">
<h2 id="help-menu-title"><strong>Fizzy do > Help</strong></h2>
<dl>
<h3>Search</h3>
<dt>Type keywords to search cards and comments</dt>
<dd>"CSS bug"</dd>
<h3>Navigate</h3>
<dt>Type a card ID to go to it</dt>
<dd>"137"</dd>
<dt>Type a name to see someones profile</dt>
<dd>"@jason"</dd>
<h3>Filter</h3>
<dt>Type card IDs to isolate them</dt>
<dd>"131, 137, 39"</dd>
<dt>Type a tag to see just tagged cards</dt>
<dd>"#design"</dd>
<h3>Commands</h3>
<dt>Type / to issue commands</dt>
<dd>"/move to Doing"</dd>
<dt>Type @ to match people</dt>
<dd>"/assign to @jason"</dd>
<dt>Type # to match tags</dt>
<dd>"/tag this #design"</dd>
<h3>Tips</h3>
<dt>Combine for powerful actions</dt>
<dd>"/move to Doing and /assign to @jason"</dd>
<dt>Or use natural language</dt>
<dd>"Show cards added by Jason this month"</dd>
</dl>
</section>
-27
View File
@@ -1,27 +0,0 @@
<%= tag.div \
id: "command-terminal",
class: "terminal full-width flex flex-column justify-end",
data: {
controller: "terminal",
terminal_dialog_outlet: "#terminal-modal",
terminal_error_class: "terminal--error",
terminal_confirmation_class: "terminal--confirmation",
terminal_help_class: "terminal--showing-help",
terminal_output_class: "terminal--showing-output",
terminal_busy_class: "terminal--busy",
toggle_class_toggle_class: "terminal--open"
} do %>
<%= tag.dialog \
id: "terminal-modal",
class: "terminal__modal panel shadow",
data: {
controller: "dialog",
dialog_target: "dialog",
dialog_modal_value: "true",
action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside" } do %>
<%= turbo_frame_tag "terminal-turbo-frame", refresh: :morph, data: { terminal_target: "modalTurboFrame" }, target: "_top" %>
<% end %>
<%= render "commands/form" %>
<% end %>
@@ -1,19 +0,0 @@
require "test_helper"
class CommandsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in_as :kevin
end
test "command that results in a redirect" do
post commands_path, params: { command: "#{cards(:logo).id}" }
assert_redirected_to cards(:logo)
end
test "command that triggers a redirect back" do
post commands_path, params: { command: "design" }
assert_redirected_to search_path(q: "design")
end
end
-22
View File
@@ -1,22 +0,0 @@
require "test_helper"
class Command::GoToCardTest < ActionDispatch::IntegrationTest
include CommandTestHelper
setup do
@card = cards(:logo)
end
test "redirect to the card perma" do
result = execute_command "#{@card.id}"
assert_equal @card, result.url
end
test "result in a regular search if the card does not exist" do
command = parse_command "123"
result = command.execute
assert_equal search_path(q: "123"), result.url
end
end