collavre 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/collavre/comments_popup.css +293 -8
- data/app/assets/stylesheets/collavre/mention_menu.css +26 -0
- data/app/assets/stylesheets/collavre/popup.css +7 -0
- data/app/assets/stylesheets/collavre/print.css +18 -0
- data/app/channels/collavre/comments_presence_channel.rb +33 -0
- data/app/components/collavre/autocomplete_popup_component.html.erb +3 -0
- data/app/components/collavre/autocomplete_popup_component.rb +18 -0
- data/app/components/collavre/command_menu_component.rb +7 -0
- data/app/components/collavre/plans_timeline_component.html.erb +1 -1
- data/app/components/collavre/plans_timeline_component.rb +29 -32
- data/app/components/collavre/user_mention_menu_component.rb +4 -5
- data/app/controllers/collavre/comments_controller.rb +111 -10
- data/app/controllers/collavre/creatives_controller.rb +8 -0
- data/app/controllers/collavre/google_auth_controller.rb +5 -1
- data/app/controllers/collavre/plans_controller.rb +65 -9
- data/app/controllers/collavre/topics_controller.rb +42 -0
- data/app/controllers/collavre/users_controller.rb +4 -14
- data/app/errors/collavre/approval_pending_error.rb +54 -0
- data/app/errors/collavre/cancelled_error.rb +9 -0
- data/app/helpers/collavre/navigation_helper.rb +3 -1
- data/app/javascript/collavre.js +1 -0
- data/app/javascript/controllers/comments/__tests__/popup_controller.test.js +2 -1
- data/app/javascript/controllers/comments/form_controller.js +2 -1
- data/app/javascript/controllers/comments/list_controller.js +185 -2
- data/app/javascript/controllers/comments/popup_controller.js +95 -20
- data/app/javascript/controllers/comments/presence_controller.js +30 -1
- data/app/javascript/controllers/comments/topics_controller.js +314 -4
- data/app/javascript/modules/__tests__/creative_progress.test.js +50 -0
- data/app/javascript/modules/command_menu.js +116 -0
- data/app/javascript/modules/creative_progress.js +14 -0
- data/app/javascript/modules/creative_row_editor.js +104 -20
- data/app/javascript/modules/plans_timeline.js +15 -4
- data/app/javascript/modules/share_modal.js +3 -0
- data/app/jobs/collavre/ai_agent_job.rb +35 -21
- data/app/models/collavre/calendar_event.rb +7 -1
- data/app/models/collavre/comment.rb +35 -2
- data/app/models/collavre/creative.rb +1 -3
- data/app/models/collavre/mcp_tool.rb +4 -0
- data/app/models/collavre/plan.rb +23 -0
- data/app/models/collavre/topic.rb +12 -0
- data/app/models/collavre/user.rb +15 -1
- data/app/services/collavre/ai_agent_service.rb +174 -66
- data/app/services/collavre/ai_client.rb +31 -2
- data/app/services/collavre/comments/action_executor.rb +47 -1
- data/app/services/collavre/comments/calendar_command.rb +117 -18
- data/app/services/collavre/google_calendar_service.rb +38 -15
- data/app/services/collavre/markdown_importer.rb +47 -8
- data/app/services/collavre/mcp_service.rb +23 -10
- data/app/services/collavre/system_events/router.rb +50 -26
- data/app/services/collavre/tools/creative_create_service.rb +97 -0
- data/app/services/collavre/tools/creative_update_service.rb +116 -0
- data/app/views/collavre/comments/_comment.html.erb +2 -2
- data/app/views/collavre/comments/_comments_popup.html.erb +40 -6
- data/app/views/collavre/comments/fullscreen.html.erb +5 -0
- data/app/views/collavre/creatives/_inline_edit_form.html.erb +11 -3
- data/app/views/collavre/creatives/_integration_modals.html.erb +6 -0
- data/app/views/collavre/creatives/_integration_triggers.html.erb +8 -0
- data/app/views/collavre/creatives/_integrations_menu.html.erb +12 -0
- data/app/views/collavre/creatives/_mobile_actions_menu.html.erb +13 -1
- data/app/views/collavre/creatives/_share_button.html.erb +1 -1
- data/app/views/collavre/creatives/index.html.erb +22 -4
- data/app/views/collavre/users/edit_ai.html.erb +15 -0
- data/app/views/collavre/users/new_ai.html.erb +15 -0
- data/app/views/layouts/collavre/chat.html.erb +46 -0
- data/config/locales/ai_agent.en.yml +15 -0
- data/config/locales/ai_agent.ko.yml +15 -0
- data/config/locales/comments.en.yml +15 -3
- data/config/locales/comments.ko.yml +15 -3
- data/config/locales/creatives.en.yml +3 -31
- data/config/locales/creatives.ko.yml +3 -27
- data/config/locales/plans.en.yml +4 -0
- data/config/locales/plans.ko.yml +4 -0
- data/config/locales/users.en.yml +3 -0
- data/config/locales/users.ko.yml +3 -0
- data/config/routes.rb +8 -3
- data/db/migrate/20260120045354_encrypt_oauth_tokens.rb +1 -1
- data/db/migrate/20260131100000_migrate_active_storage_attachment_record_types.rb +21 -0
- data/db/migrate/20260201100000_make_google_event_id_nullable.rb +5 -0
- data/lib/collavre/engine.rb +171 -6
- data/lib/collavre/integration_registry.rb +129 -0
- data/lib/collavre/version.rb +1 -1
- data/lib/collavre.rb +2 -0
- data/lib/navigation/registry.rb +130 -0
- metadata +22 -15
- data/app/components/collavre/user_mention_menu_component.html.erb +0 -3
- data/app/controllers/collavre/notion_auth_controller.rb +0 -25
- data/app/jobs/collavre/notion_export_job.rb +0 -30
- data/app/jobs/collavre/notion_sync_job.rb +0 -48
- data/app/models/collavre/notion_account.rb +0 -17
- data/app/models/collavre/notion_block_link.rb +0 -10
- data/app/models/collavre/notion_page_link.rb +0 -19
- data/app/services/collavre/notion_client.rb +0 -231
- data/app/services/collavre/notion_creative_exporter.rb +0 -296
- data/app/services/collavre/notion_service.rb +0 -249
- data/app/views/collavre/creatives/_notion_integration_modal.html.erb +0 -90
- data/db/migrate/20241201000000_create_notion_integrations.rb +0 -29
- data/db/migrate/20250312000000_create_notion_block_links.rb +0 -16
- data/db/migrate/20250312010000_allow_multiple_notion_blocks_per_creative.rb +0 -5
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<%# Render modals for registered integrations %>
|
|
2
|
+
<% Collavre::IntegrationRegistry.each do |integration| %>
|
|
3
|
+
<% if integration.enabled_for?(creative) && integration.creative_menu_partial.present? %>
|
|
4
|
+
<%= render integration.creative_menu_partial, creative: creative, integration: integration %>
|
|
5
|
+
<% end %>
|
|
6
|
+
<% end %>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# Render hidden trigger buttons for registered integrations %>
|
|
2
|
+
<% Collavre::IntegrationRegistry.each do |integration| %>
|
|
3
|
+
<% if integration.enabled_for?(creative) %>
|
|
4
|
+
<button id="<%= integration.name %>-integration-btn"
|
|
5
|
+
data-creative-id="<%= creative&.id %>"
|
|
6
|
+
style="display:none;"></button>
|
|
7
|
+
<% end %>
|
|
8
|
+
<% end %>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%# Render integration menu items from IntegrationRegistry %>
|
|
2
|
+
<% Collavre::IntegrationRegistry.each do |integration| %>
|
|
3
|
+
<% if integration.enabled_for?(creative) %>
|
|
4
|
+
<button type="button"
|
|
5
|
+
class="popup-menu-item"
|
|
6
|
+
data-controller="click-target"
|
|
7
|
+
data-click-target-id-value="<%= integration.name %>-integration-btn"
|
|
8
|
+
data-action="click->click-target#trigger">
|
|
9
|
+
<%= integration.label %>
|
|
10
|
+
</button>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
@@ -10,8 +10,20 @@
|
|
|
10
10
|
<button type="button" class="popup-menu-item" data-controller="click-target" data-click-target-id-value="share-creative-btn" data-action="click->click-target#trigger"><%= t('collavre.creatives.index.share') %></button>
|
|
11
11
|
<% end %>
|
|
12
12
|
<% if can_manage_integrations %>
|
|
13
|
+
<%# Legacy hardcoded integrations %>
|
|
13
14
|
<button type="button" class="popup-menu-item" data-controller="click-target" data-click-target-id-value="github-integration-btn" data-action="click->click-target#trigger"><%= t('collavre.creatives.index.integrations', default: '연동') %> - Github</button>
|
|
14
|
-
|
|
15
|
+
<%# Dynamically registered integrations %>
|
|
16
|
+
<% Collavre::IntegrationRegistry.each do |integration| %>
|
|
17
|
+
<% if integration.enabled_for?(current_creative) %>
|
|
18
|
+
<button type="button"
|
|
19
|
+
class="popup-menu-item"
|
|
20
|
+
data-controller="click-target"
|
|
21
|
+
data-click-target-id-value="<%= integration.name %>-integration-btn"
|
|
22
|
+
data-action="click->click-target#trigger">
|
|
23
|
+
<%= t('collavre.creatives.index.integrations', default: '연동') %> - <%= integration.label %>
|
|
24
|
+
</button>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
15
27
|
<% end %>
|
|
16
28
|
<% if @parent_creative.present? %>
|
|
17
29
|
<%= button_to t('collavre.creatives.index.slide_view'), slide_view_creative_path(@parent_creative), method: :get, class: 'popup-menu-item' %>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<span aria-hidden="true"><%= svg_tag 'share.svg', class: 'icon-up', width: 22, height: 20 %></span>
|
|
3
3
|
</button>
|
|
4
4
|
<!-- Share Creative Modal -->
|
|
5
|
-
<div id="share-creative-modal" style="display:none;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:
|
|
5
|
+
<div id="share-creative-modal" style="display:none;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:1100;align-items:center;justify-content:center;" data-creative-id="<%= (@parent_creative || @creative).id %>">
|
|
6
6
|
<div class="popup-box" style="min-width:320px;max-width:90vw;">
|
|
7
7
|
<button id="close-share-modal" class="popup-close-btn">×</button>
|
|
8
8
|
<h2><%= t('collavre.creatives.index.share_creative') %></h2>
|
|
@@ -33,8 +33,10 @@
|
|
|
33
33
|
align: :left,
|
|
34
34
|
button_classes: 'desktop-only'
|
|
35
35
|
) do %>
|
|
36
|
+
<%# Legacy hardcoded integrations (to be migrated to IntegrationRegistry) %>
|
|
36
37
|
<button type="button" class="popup-menu-item" data-controller="click-target" data-click-target-id-value="github-integration-btn" data-action="click->click-target#trigger">Github</button>
|
|
37
|
-
|
|
38
|
+
<%# Dynamically registered integrations %>
|
|
39
|
+
<%= render 'integrations_menu', creative: current_creative %>
|
|
38
40
|
<% end %>
|
|
39
41
|
<% end %>
|
|
40
42
|
|
|
@@ -64,8 +66,10 @@
|
|
|
64
66
|
<%= render 'import_upload_zone' %>
|
|
65
67
|
|
|
66
68
|
<% if can_manage_integrations %>
|
|
69
|
+
<%# Legacy hardcoded integration triggers %>
|
|
67
70
|
<button id="github-integration-btn" data-creative-id="<%= current_creative&.id %>" style="display:none;"></button>
|
|
68
|
-
|
|
71
|
+
<%# Dynamically registered integration triggers %>
|
|
72
|
+
<%= render 'integration_triggers', creative: current_creative %>
|
|
69
73
|
<% end %>
|
|
70
74
|
|
|
71
75
|
|
|
@@ -81,7 +85,19 @@
|
|
|
81
85
|
value="<%= label.id %>">
|
|
82
86
|
|
|
83
87
|
<%= "##{strip_tags(label.name)}" %>
|
|
84
|
-
<% if label.type == "Plan" %>
|
|
88
|
+
<% if label.type == "Plan" %>
|
|
89
|
+
<% if @parent_creative&.has_permission?(Current.user, :write) %>
|
|
90
|
+
<%= form_with(model: label, url: collavre.plan_path(label), method: :patch, local: true, class: "plan-tag-date-form") do |form| %>
|
|
91
|
+
<%= hidden_field_tag :creative_id, @parent_creative.id %>
|
|
92
|
+
🗓
|
|
93
|
+
<%= form.date_field :start_date, value: label.start_date, class: "plan-tag-date-input" %>
|
|
94
|
+
<%= form.date_field :target_date, value: label.target_date, class: "plan-tag-date-input" %>
|
|
95
|
+
<%= form.submit t("collavre.plans.update", default: "Update"), class: "plan-tag-date-submit" %>
|
|
96
|
+
<% end %>
|
|
97
|
+
<% else %>
|
|
98
|
+
🗓<%= label.target_date %>
|
|
99
|
+
<% end %>
|
|
100
|
+
<% end %>
|
|
85
101
|
|
|
86
102
|
<% end %>
|
|
87
103
|
<% if labels.present? %>
|
|
@@ -186,7 +202,9 @@
|
|
|
186
202
|
|
|
187
203
|
<%= render 'set_plan_modal' %>
|
|
188
204
|
<% if can_manage_integrations %>
|
|
205
|
+
<%# Legacy hardcoded integration modals %>
|
|
189
206
|
<%= render 'github_integration_modal', creative: current_creative %>
|
|
190
|
-
|
|
207
|
+
<%# Dynamically registered integration modals %>
|
|
208
|
+
<%= render 'integration_modals', creative: current_creative %>
|
|
191
209
|
<% end %>
|
|
192
210
|
</div>
|
|
@@ -17,6 +17,15 @@
|
|
|
17
17
|
<small class="form-text text-muted">Liquid expression to determine if this agent should handle an event. Example: <code>chat.mentioned_user.id == agent.id</code></small>
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
+
<div class="form-group">
|
|
21
|
+
<%= form.label :llm_vendor, t('collavre.users.new_ai.vendor_label', default: 'LLM Provider') %>
|
|
22
|
+
<%= form.select :llm_vendor, options_for_select([
|
|
23
|
+
["Google (Gemini)", "google"],
|
|
24
|
+
["OpenClaw", "openclaw"]
|
|
25
|
+
], @user.llm_vendor || "google"), {}, class: "stacked-form-control" %>
|
|
26
|
+
<small class="form-text text-muted"><%= t('collavre.users.new_ai.vendor_help', default: 'Select the AI provider for this agent') %></small>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
20
29
|
<div class="form-group">
|
|
21
30
|
<%= form.label :llm_model, t('collavre.users.new_ai.model_label') %>
|
|
22
31
|
<div style="position: relative;"
|
|
@@ -41,6 +50,12 @@
|
|
|
41
50
|
<small class="form-text text-muted"><%= t('collavre.users.new_ai.api_key_help') %></small>
|
|
42
51
|
</div>
|
|
43
52
|
|
|
53
|
+
<div class="form-group">
|
|
54
|
+
<%= form.label :gateway_url, t('collavre.users.new_ai.gateway_url_label', default: 'Gateway URL') %>
|
|
55
|
+
<%= form.url_field :gateway_url, class: "stacked-form-control", placeholder: "http://localhost:18789" %>
|
|
56
|
+
<small class="form-text text-muted"><%= t('collavre.users.new_ai.gateway_url_help', default: 'Required for OpenClaw. The URL of your OpenClaw gateway.') %></small>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
44
59
|
<div class="form-group">
|
|
45
60
|
<label class="form-label"><%= t('collavre.users.edit_ai.tools_title') %></label>
|
|
46
61
|
<p class="text-muted small"><%= t('collavre.users.edit_ai.tools_description') %></p>
|
|
@@ -22,6 +22,15 @@
|
|
|
22
22
|
<small class="form-text text-muted">Liquid expression to determine if this agent should handle an event. Example: <code>chat.mentioned_user.id == agent.id</code></small>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
+
<div class="form-group">
|
|
26
|
+
<%= form.label :llm_vendor, t('collavre.users.new_ai.vendor_label', default: 'LLM Provider') %>
|
|
27
|
+
<%= form.select :llm_vendor, options_for_select([
|
|
28
|
+
["Google (Gemini)", "google"],
|
|
29
|
+
["OpenClaw", "openclaw"]
|
|
30
|
+
], "google"), {}, class: "stacked-form-control" %>
|
|
31
|
+
<small class="form-text text-muted"><%= t('collavre.users.new_ai.vendor_help', default: 'Select the AI provider for this agent') %></small>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
25
34
|
<div class="form-group">
|
|
26
35
|
<%= form.label :llm_model, t('collavre.users.new_ai.model_label') %>
|
|
27
36
|
<div style="position: relative;"
|
|
@@ -46,6 +55,12 @@
|
|
|
46
55
|
<small class="form-text text-muted"><%= t('collavre.users.new_ai.api_key_help') %></small>
|
|
47
56
|
</div>
|
|
48
57
|
|
|
58
|
+
<div class="form-group">
|
|
59
|
+
<%= form.label :gateway_url, t('collavre.users.new_ai.gateway_url_label', default: 'Gateway URL') %>
|
|
60
|
+
<%= form.url_field :gateway_url, class: "stacked-form-control", placeholder: "http://localhost:18789" %>
|
|
61
|
+
<small class="form-text text-muted"><%= t('collavre.users.new_ai.gateway_url_help', default: 'Required for OpenClaw. The URL of your OpenClaw gateway.') %></small>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
49
64
|
<div class="form-group">
|
|
50
65
|
<label class="form-label"><%= t('collavre.users.edit_ai.tools_title') %></label>
|
|
51
66
|
<p class="text-muted small"><%= t('collavre.users.edit_ai.tools_description') %></p>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title><%= content_for(:title) || t('app.name') %></title>
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
7
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
8
|
+
<meta name="app-version" content="<%= Rails.application.config.app_version %>">
|
|
9
|
+
<%= csrf_meta_tags %>
|
|
10
|
+
<%= csp_meta_tag %>
|
|
11
|
+
|
|
12
|
+
<%= yield :head %>
|
|
13
|
+
|
|
14
|
+
<link rel="icon" href="/icon-1e3cf549d2.png" type="image/png">
|
|
15
|
+
<link rel="icon" href="/icon-1e3cf549d2.svg" type="image/svg+xml">
|
|
16
|
+
<link rel="apple-touch-icon" href="/icon-1e3cf549d2.png">
|
|
17
|
+
|
|
18
|
+
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
|
|
19
|
+
<%= stylesheet_link_tag "collavre/creatives" %>
|
|
20
|
+
<%= stylesheet_link_tag "collavre/actiontext" %>
|
|
21
|
+
<%= stylesheet_link_tag "collavre/dark_mode" %>
|
|
22
|
+
<%= stylesheet_link_tag "collavre/popup" %>
|
|
23
|
+
<%= stylesheet_link_tag "collavre/comments_popup" %>
|
|
24
|
+
|
|
25
|
+
<%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true, type: "module" %>
|
|
26
|
+
|
|
27
|
+
<% if Current.user&.theme.present? && !%w[light dark].include?(Current.user.theme) %>
|
|
28
|
+
<% if (custom_theme = UserTheme.find_by(id: Current.user.theme)) %>
|
|
29
|
+
<style id="user-theme-styles" data-turbo-track="reload">
|
|
30
|
+
body {
|
|
31
|
+
<% custom_theme.variables.each do |key, value| %>
|
|
32
|
+
<%= key %>: <%= value %> !important;
|
|
33
|
+
<% end %>
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
36
|
+
<% end %>
|
|
37
|
+
<% end %>
|
|
38
|
+
</head>
|
|
39
|
+
<body class="chat-fullscreen<%= ' dark-mode' if Current.user&.theme == 'dark' %><%= ' light-mode' if Current.user&.theme == 'light' %>" data-current-user-id="<%= Current.user&.id %>" data-controller="action-text-attachment-link" data-action="click->action-text-attachment-link#download">
|
|
40
|
+
<main>
|
|
41
|
+
<%= yield %>
|
|
42
|
+
</main>
|
|
43
|
+
|
|
44
|
+
<%= render "collavre/comments/reaction_picker" %>
|
|
45
|
+
</body>
|
|
46
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
en:
|
|
2
|
+
collavre:
|
|
3
|
+
ai_agent:
|
|
4
|
+
approval:
|
|
5
|
+
message: |
|
|
6
|
+
🔧 **Tool Approval Required**
|
|
7
|
+
|
|
8
|
+
**%{tool_name}** wants to execute with the following arguments:
|
|
9
|
+
|
|
10
|
+
```json
|
|
11
|
+
%{arguments}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Please approve or reject this action.
|
|
15
|
+
no_arguments: "(no arguments)"
|
|
@@ -8,9 +8,6 @@ en:
|
|
|
8
8
|
github_auth:
|
|
9
9
|
login_first: Please sign in first.
|
|
10
10
|
connected: Github account connected successfully.
|
|
11
|
-
notion_auth:
|
|
12
|
-
login_first: Please sign in first.
|
|
13
|
-
connected: Notion account connected successfully.
|
|
14
11
|
comments:
|
|
15
12
|
reaction_invalid: Invalid reaction.
|
|
16
13
|
invalid_topic: Topic does not belong to this creative.
|
|
@@ -70,17 +67,31 @@ en:
|
|
|
70
67
|
move_button: Move
|
|
71
68
|
move_no_selection: Select at least one message to move.
|
|
72
69
|
move_error: Unable to move messages.
|
|
70
|
+
add_participant: Add user
|
|
71
|
+
hint_drag_topic: "🎯 Drag → Move to topic"
|
|
72
|
+
hint_move_button: "📤 Move button → Another chat"
|
|
73
|
+
fullscreen: Full screen
|
|
74
|
+
exit_fullscreen: Exit full screen
|
|
73
75
|
move_invalid_target: Select a valid creative to move messages to.
|
|
76
|
+
move_invalid_topic: Invalid topic selected.
|
|
74
77
|
move_not_allowed: You do not have permission to move these messages.
|
|
75
78
|
select_label: Select message
|
|
76
79
|
add_reaction: Add reaction
|
|
77
80
|
add_reaction_button: "+"
|
|
81
|
+
command_menu:
|
|
82
|
+
calendar_description: "Create a Google Calendar event."
|
|
83
|
+
calendar_args: "YYYY-MM-DD@HH:MM memo (today/tomorrow, +3days, +2weeks, +1months, +1years, +mon)"
|
|
78
84
|
calendar_command:
|
|
79
85
|
event_created: 'event created: [Google Calendar event](%{url})'
|
|
86
|
+
event_created_local: 'event created (local only - connect Google Calendar to sync)'
|
|
87
|
+
event_created_sync_failed: 'event created (Google Calendar sync failed - please reconnect your Google account)'
|
|
80
88
|
read_by: Read by %{name}
|
|
81
89
|
activity_logs_summary: Activity Logs
|
|
82
90
|
calendar_events:
|
|
83
91
|
deleted: Calendar event deleted.
|
|
92
|
+
google_calendar:
|
|
93
|
+
errors:
|
|
94
|
+
not_connected: Google Calendar is not connected. Please connect your Google account first.
|
|
84
95
|
inbox:
|
|
85
96
|
mark_read: Read
|
|
86
97
|
mark_unread: Unread
|
|
@@ -96,6 +107,7 @@ en:
|
|
|
96
107
|
comment_content_unavailable: "(comment unavailable)"
|
|
97
108
|
tool_approval_needed: Tool '%{tool_name}' has been detected/updated. Please approve
|
|
98
109
|
it to activate.
|
|
110
|
+
approval_requested: '%{user} requested approval to execute tool "%{tool_name}" in "%{creative}".'
|
|
99
111
|
emails:
|
|
100
112
|
index_title: Emails
|
|
101
113
|
list:
|
|
@@ -8,9 +8,6 @@ ko:
|
|
|
8
8
|
github_auth:
|
|
9
9
|
login_first: 먼저 로그인해주세요.
|
|
10
10
|
connected: Github 계정이 연동되었습니다.
|
|
11
|
-
notion_auth:
|
|
12
|
-
login_first: 먼저 로그인해주세요.
|
|
13
|
-
connected: Notion 계정이 연동되었습니다.
|
|
14
11
|
comments:
|
|
15
12
|
reaction_invalid: 잘못된 리액션입니다.
|
|
16
13
|
invalid_topic: 토픽이 이 크리에이티브에 속하지 않습니다.
|
|
@@ -67,17 +64,31 @@ ko:
|
|
|
67
64
|
move_button: 이동
|
|
68
65
|
move_no_selection: 이동할 메시지를 선택해주세요.
|
|
69
66
|
move_error: 메시지를 이동할 수 없습니다.
|
|
67
|
+
add_participant: 사용자 추가
|
|
68
|
+
hint_drag_topic: "🎯 드래그 → 토픽 이동"
|
|
69
|
+
hint_move_button: "📤 이동 버튼 → 다른 채팅창"
|
|
70
|
+
fullscreen: 전체 화면
|
|
71
|
+
exit_fullscreen: 전체 화면 종료
|
|
70
72
|
move_invalid_target: 이동할 크리에이티브를 선택해주세요.
|
|
73
|
+
move_invalid_topic: 유효하지 않은 토픽입니다.
|
|
71
74
|
move_not_allowed: 이 메시지를 이동할 권한이 없습니다.
|
|
72
75
|
select_label: 메시지 선택
|
|
73
76
|
add_reaction: 리액션 추가
|
|
74
77
|
add_reaction_button: "+"
|
|
78
|
+
command_menu:
|
|
79
|
+
calendar_description: 구글 캘린더 이벤트를 생성합니다.
|
|
80
|
+
calendar_args: "YYYY-MM-DD@HH:MM 메모 (today/tomorrow, +3days, +2weeks, +1months, +1years, +mon/+월)"
|
|
75
81
|
calendar_command:
|
|
76
82
|
event_created: '이벤트가 생성되었습니다: [구글 캘린더 이벤트](%{url})'
|
|
83
|
+
event_created_local: '이벤트가 생성되었습니다 (로컬 전용 - 구글 캘린더 연동 시 동기화됩니다)'
|
|
84
|
+
event_created_sync_failed: '이벤트가 생성되었습니다 (구글 캘린더 동기화 실패 - 구글 계정을 다시 연동해주세요)'
|
|
77
85
|
read_by: "%{name} 님이 읽음"
|
|
78
86
|
activity_logs_summary: 활동 기록
|
|
79
87
|
calendar_events:
|
|
80
88
|
deleted: 캘린더 이벤트가 삭제되었습니다.
|
|
89
|
+
google_calendar:
|
|
90
|
+
errors:
|
|
91
|
+
not_connected: 구글 캘린더가 연동되지 않았습니다. 먼저 구글 계정을 연동해주세요.
|
|
81
92
|
inbox:
|
|
82
93
|
mark_read: 읽음
|
|
83
94
|
mark_unread: 안읽음
|
|
@@ -92,6 +103,7 @@ ko:
|
|
|
92
103
|
삭제했습니다: %{comment_content}'
|
|
93
104
|
comment_content_unavailable: "(삭제된 댓글 내용을 표시할 수 없습니다)"
|
|
94
105
|
tool_approval_needed: 도구 '%{tool_name}'가 감지/업데이트되었습니다. 활성화하려면 승인해주세요.
|
|
106
|
+
approval_requested: '%{user}님이 "%{creative}"에서 도구 "%{tool_name}" 실행 승인을 요청했습니다.'
|
|
95
107
|
emails:
|
|
96
108
|
index_title: 이메일
|
|
97
109
|
list:
|
|
@@ -98,37 +98,6 @@ en:
|
|
|
98
98
|
it if needed.
|
|
99
99
|
github_integration_prompt_help: 'Use the placeholders below to inject runtime
|
|
100
100
|
details as needed:'
|
|
101
|
-
notion_integration_saved: Notion integration saved successfully.
|
|
102
|
-
notion_integration_login_required: Sign in with your Notion account to start
|
|
103
|
-
the integration.
|
|
104
|
-
notion_integration_missing_creative: No Creative selected for integration.
|
|
105
|
-
notion_integration_existing_message: You're already connected to Notion pages
|
|
106
|
-
below.
|
|
107
|
-
notion_integration_delete_confirm: Do you want to remove the Notion integration?
|
|
108
|
-
notion_integration_delete_success: Notion integration removed successfully.
|
|
109
|
-
notion_integration_delete_error: Failed to remove the Notion integration.
|
|
110
|
-
notion_integration_delete_button: Remove integration
|
|
111
|
-
notion_export_success: Creative exported to Notion successfully.
|
|
112
|
-
notion_sync_success: Creative synced to Notion successfully.
|
|
113
|
-
notion_integration_title: Configure Notion integration
|
|
114
|
-
notion_integration_connect: Sign in with your Notion account to start exporting.
|
|
115
|
-
notion_login_button: Sign in with Notion
|
|
116
|
-
notion_integration_existing_intro: 'Linked Notion pages:'
|
|
117
|
-
notion_sync_button: Sync to Notion
|
|
118
|
-
notion_integration_workspace: Your Notion workspace is connected. Choose how
|
|
119
|
-
to export your creative.
|
|
120
|
-
notion_export_option: 'Export option:'
|
|
121
|
-
notion_export_new_page: Create new page
|
|
122
|
-
notion_export_under_page: Create as subpage under existing page
|
|
123
|
-
notion_parent_page: 'Parent page:'
|
|
124
|
-
notion_loading: Loading pages...
|
|
125
|
-
notion_integration_summary: 'Ready to export your creative tree to Notion:'
|
|
126
|
-
notion_creative_title: 'Root Creative:'
|
|
127
|
-
notion_workspace: 'Workspace:'
|
|
128
|
-
notion_export_as: 'Export as:'
|
|
129
|
-
notion_tree_note: This will export the selected creative and all its descendants
|
|
130
|
-
as a structured document.
|
|
131
|
-
notion_export_button: Export to Notion
|
|
132
101
|
plan_tags_applied: Plan tags applied to selected creatives.
|
|
133
102
|
plan_tag_failed: Please select a plan and at least one creative.
|
|
134
103
|
plan_tags_removed: Plan tag removed from selected creatives.
|
|
@@ -136,6 +105,9 @@ en:
|
|
|
136
105
|
select_plan: Select Plan
|
|
137
106
|
remove_plan: Remove Plan
|
|
138
107
|
add_plan: Add Plan
|
|
108
|
+
progress_complete: Complete
|
|
109
|
+
progress_incomplete: Incomplete
|
|
110
|
+
progress_complete_children_alert: Marking this creative complete will also mark all child creatives complete.
|
|
139
111
|
set_plan_title: Set Plan for Selected Creative
|
|
140
112
|
are_you_sure_delete_share: Are you sure delete share?
|
|
141
113
|
share_deleted: The share are deleted.
|
|
@@ -85,33 +85,6 @@ ko:
|
|
|
85
85
|
github_integration_existing_intro: '이미 연동된 Repository 목록입니다:'
|
|
86
86
|
github_integration_prompt_title: Gemini 분석 프롬프트를 확인하고 필요시 수정하세요.
|
|
87
87
|
github_integration_prompt_help: '아래 플레이스홀더를 사용하여 런타임 정보를 삽입할 수 있습니다:'
|
|
88
|
-
notion_integration_saved: Notion 연동이 저장되었습니다.
|
|
89
|
-
notion_integration_login_required: Notion 계정으로 로그인하여 연동을 시작하세요.
|
|
90
|
-
notion_integration_missing_creative: 연동할 Creative가 선택되지 않았습니다.
|
|
91
|
-
notion_integration_existing_message: 이미 아래 Notion 페이지와 연동 중입니다.
|
|
92
|
-
notion_integration_delete_confirm: Notion 연동을 삭제하시겠습니까?
|
|
93
|
-
notion_integration_delete_success: Notion 연동이 삭제되었습니다.
|
|
94
|
-
notion_integration_delete_error: Notion 연동 삭제에 실패했습니다.
|
|
95
|
-
notion_integration_delete_button: 연동 삭제
|
|
96
|
-
notion_export_success: Creative가 Notion으로 내보내기 되었습니다.
|
|
97
|
-
notion_sync_success: Creative가 Notion과 동기화되었습니다.
|
|
98
|
-
notion_integration_title: Notion 연동 설정
|
|
99
|
-
notion_integration_connect: Notion 계정으로 로그인하여 내보내기를 시작하세요.
|
|
100
|
-
notion_login_button: Notion 계정으로 로그인
|
|
101
|
-
notion_integration_existing_intro: '연동된 Notion 페이지:'
|
|
102
|
-
notion_sync_button: Notion으로 동기화
|
|
103
|
-
notion_integration_workspace: Notion 워크스페이스가 연결되었습니다. 내보내기 방법을 선택하세요.
|
|
104
|
-
notion_export_option: '내보내기 옵션:'
|
|
105
|
-
notion_export_new_page: 새 페이지 생성
|
|
106
|
-
notion_export_under_page: 기존 페이지 하위에 생성
|
|
107
|
-
notion_parent_page: '상위 페이지:'
|
|
108
|
-
notion_loading: 페이지 로딩 중...
|
|
109
|
-
notion_integration_summary: 'Creative 트리를 Notion으로 내보낼 준비가 되었습니다:'
|
|
110
|
-
notion_creative_title: '루트 Creative:'
|
|
111
|
-
notion_workspace: '워크스페이스:'
|
|
112
|
-
notion_export_as: '내보내기 형태:'
|
|
113
|
-
notion_tree_note: 선택한 크리에이티브와 모든 하위 항목이 구조화된 문서로 내보내집니다.
|
|
114
|
-
notion_export_button: Notion으로 내보내기
|
|
115
88
|
search_placeholder: 크리에이티브 검색...
|
|
116
89
|
plan_tags_applied: 선택한 크리에이티브에 플랜 태그가 적용되었습니다.
|
|
117
90
|
plan_tag_failed: 플랜과 하나 이상의 크리에이티브를 선택하세요.
|
|
@@ -120,6 +93,9 @@ ko:
|
|
|
120
93
|
select_plan: 계획 선택
|
|
121
94
|
remove_plan: 계획 제거
|
|
122
95
|
add_plan: 계획 추가
|
|
96
|
+
progress_complete: 완료
|
|
97
|
+
progress_incomplete: 미완료
|
|
98
|
+
progress_complete_children_alert: 하위 크리에이티브도 모두 완료로 표시됩니다.
|
|
123
99
|
set_plan_title: 선택된 크리에이티브에 대한 계획 설정
|
|
124
100
|
are_you_sure_delete_share: 공유를 삭제하시겠습니까?
|
|
125
101
|
share_deleted: 공유가 삭제 되었습니다.
|
data/config/locales/plans.en.yml
CHANGED
|
@@ -3,10 +3,14 @@ en:
|
|
|
3
3
|
collavre:
|
|
4
4
|
plans:
|
|
5
5
|
add_plan: Add Plan
|
|
6
|
+
start_date: Start Date
|
|
6
7
|
target_date: Target Date
|
|
7
8
|
plan_name: Plan Name
|
|
8
9
|
created: Plan was successfully created.
|
|
9
10
|
deleted: Plan deleted.
|
|
11
|
+
updated: Plan updated.
|
|
12
|
+
update: Update
|
|
13
|
+
update_forbidden: You do not have permission to update this plan.
|
|
10
14
|
delete_confirm: Are you sure you want to delete this plan?
|
|
11
15
|
today: Today
|
|
12
16
|
select_creative: Select Creative
|
data/config/locales/plans.ko.yml
CHANGED
|
@@ -3,10 +3,14 @@ ko:
|
|
|
3
3
|
collavre:
|
|
4
4
|
plans:
|
|
5
5
|
add_plan: 계획 추가
|
|
6
|
+
start_date: 시작 날짜
|
|
6
7
|
target_date: 목표 날짜
|
|
7
8
|
plan_name: 계획 이름
|
|
8
9
|
created: 계획이 성공적으로 생성되었습니다.
|
|
9
10
|
deleted: 계획이 삭제되었습니다.
|
|
11
|
+
updated: 계획이 업데이트되었습니다.
|
|
12
|
+
update: 업데이트
|
|
13
|
+
update_forbidden: 이 계획을 업데이트할 권한이 없습니다.
|
|
10
14
|
delete_confirm: 이 계획을 삭제하시겠습니까?
|
|
11
15
|
today: 오늘
|
|
12
16
|
select_creative: 크리에이티브 선택
|
data/config/locales/users.en.yml
CHANGED
|
@@ -22,10 +22,13 @@ en:
|
|
|
22
22
|
name_label: Name
|
|
23
23
|
system_prompt_label: System Prompt
|
|
24
24
|
vendor_label: LLM Vendor
|
|
25
|
+
vendor_help: Select the AI provider for this agent
|
|
25
26
|
model_label: Model
|
|
26
27
|
api_key_label: API Key
|
|
27
28
|
api_key_help: If provided, this key will be used instead of the system default.
|
|
28
29
|
Stored encrypted.
|
|
30
|
+
gateway_url_label: Gateway URL
|
|
31
|
+
gateway_url_help: Required for OpenClaw. The URL of your OpenClaw gateway.
|
|
29
32
|
searchable_label: Allow this AI to be searchable and mentionable
|
|
30
33
|
searchable_help: When enabled, others can find and mention this AI by name.
|
|
31
34
|
submit: Add AI Agent
|
data/config/locales/users.ko.yml
CHANGED
|
@@ -21,9 +21,12 @@ ko:
|
|
|
21
21
|
name_label: 이름
|
|
22
22
|
system_prompt_label: 시스템 프롬프트
|
|
23
23
|
vendor_label: LLM 벤더
|
|
24
|
+
vendor_help: 이 에이전트에 사용할 AI 제공업체를 선택하세요
|
|
24
25
|
model_label: 모델
|
|
25
26
|
api_key_label: API Key
|
|
26
27
|
api_key_help: 입력하면 시스템 기본값 대신 이 키가 사용됩니다. 암호화되어 저장됩니다.
|
|
28
|
+
gateway_url_label: Gateway URL
|
|
29
|
+
gateway_url_help: OpenClaw 사용 시 필수입니다. OpenClaw 게이트웨이의 URL을 입력하세요.
|
|
27
30
|
searchable_label: 이 AI를 검색 및 멘션 가능하게 허용
|
|
28
31
|
searchable_help: 활성화하면 다른 사용자가 이름으로 이 AI를 찾고 멘션할 수 있습니다.
|
|
29
32
|
submit: AI 에이전트 추가
|
data/config/routes.rb
CHANGED
|
@@ -25,7 +25,6 @@ Collavre::Engine.routes.draw do
|
|
|
25
25
|
# OAuth callback routes (paths match OmniAuth provider names)
|
|
26
26
|
match "/auth/google_oauth2/callback", to: "google_auth#callback", via: [ :get, :post ]
|
|
27
27
|
match "/auth/github/callback", to: "github_auth#callback", via: [ :get, :post ]
|
|
28
|
-
match "/auth/notion/callback", to: "notion_auth#callback", via: [ :get, :post ]
|
|
29
28
|
|
|
30
29
|
delete "/attachments/:signed_id", to: "attachments#destroy", as: :attachment
|
|
31
30
|
|
|
@@ -37,7 +36,7 @@ Collavre::Engine.routes.draw do
|
|
|
37
36
|
get :count, on: :collection
|
|
38
37
|
end
|
|
39
38
|
|
|
40
|
-
resources :plans, only: [ :create, :destroy, :index ]
|
|
39
|
+
resources :plans, only: [ :create, :destroy, :index, :update ]
|
|
41
40
|
|
|
42
41
|
resources :user_themes, only: [ :index, :create, :destroy ] do
|
|
43
42
|
member do
|
|
@@ -50,7 +49,11 @@ Collavre::Engine.routes.draw do
|
|
|
50
49
|
|
|
51
50
|
resources :creatives do
|
|
52
51
|
resources :creative_shares, only: [ :create, :destroy ]
|
|
53
|
-
resources :topics, only: [ :index, :create, :destroy ]
|
|
52
|
+
resources :topics, only: [ :index, :create, :update, :destroy ] do
|
|
53
|
+
collection do
|
|
54
|
+
post :reorder
|
|
55
|
+
end
|
|
56
|
+
end
|
|
54
57
|
resources :comments, only: [ :index, :create, :destroy, :show, :update ] do
|
|
55
58
|
member do
|
|
56
59
|
post :convert
|
|
@@ -64,7 +67,9 @@ Collavre::Engine.routes.draw do
|
|
|
64
67
|
|
|
65
68
|
collection do
|
|
66
69
|
get :participants
|
|
70
|
+
get :fullscreen
|
|
67
71
|
post :move
|
|
72
|
+
get :commands
|
|
68
73
|
end
|
|
69
74
|
end
|
|
70
75
|
collection do
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class MigrateActiveStorageAttachmentRecordTypes < ActiveRecord::Migration[8.1]
|
|
2
|
+
def up
|
|
3
|
+
return unless table_exists?(:active_storage_attachments)
|
|
4
|
+
|
|
5
|
+
migrate_record_type("User", "Collavre::User")
|
|
6
|
+
migrate_record_type("Comment", "Collavre::Comment")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def down
|
|
10
|
+
return unless table_exists?(:active_storage_attachments)
|
|
11
|
+
|
|
12
|
+
migrate_record_type("Collavre::User", "User")
|
|
13
|
+
migrate_record_type("Collavre::Comment", "Comment")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def migrate_record_type(from, to)
|
|
19
|
+
ActiveStorage::Attachment.where(record_type: from).update_all(record_type: to)
|
|
20
|
+
end
|
|
21
|
+
end
|