collavre 0.5.0 → 0.7.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/comment_versions.css +76 -0
- data/app/assets/stylesheets/collavre/comments_popup.css +347 -37
- data/app/assets/stylesheets/collavre/creatives.css +73 -1
- data/app/assets/stylesheets/collavre/org_chart.css +319 -0
- data/app/assets/stylesheets/collavre/popup.css +68 -1
- data/app/controllers/collavre/application_controller.rb +13 -0
- data/app/controllers/collavre/comments/versions_controller.rb +82 -0
- data/app/controllers/collavre/comments_controller.rb +14 -153
- data/app/controllers/collavre/concerns/exportable.rb +30 -0
- data/app/controllers/collavre/concerns/shareable.rb +28 -0
- data/app/controllers/collavre/concerns/slide_viewable.rb +37 -0
- data/app/controllers/collavre/concerns/tree_manageable.rb +141 -0
- data/app/controllers/collavre/creative_imports_controller.rb +6 -0
- data/app/controllers/collavre/creative_invitations_controller.rb +46 -0
- data/app/controllers/collavre/creative_plans_controller.rb +1 -1
- data/app/controllers/collavre/creative_shares_controller.rb +84 -14
- data/app/controllers/collavre/creatives_controller.rb +70 -194
- data/app/controllers/collavre/google_auth_controller.rb +3 -0
- data/app/controllers/collavre/invites_controller.rb +2 -1
- data/app/controllers/collavre/sessions_controller.rb +3 -0
- data/app/controllers/collavre/topics_controller.rb +39 -2
- data/app/controllers/collavre/users_controller.rb +5 -404
- data/app/controllers/concerns/collavre/comments/approval_actions.rb +108 -0
- data/app/controllers/concerns/collavre/comments/batch_operations.rb +55 -0
- data/app/controllers/concerns/collavre/comments/conversion.rb +46 -0
- data/app/controllers/concerns/collavre/users_controller/admin_operations.rb +74 -0
- data/app/controllers/concerns/collavre/users_controller/ai_user_management.rb +119 -0
- data/app/controllers/concerns/collavre/users_controller/contact_management.rb +166 -0
- data/app/controllers/concerns/collavre/users_controller/profile_and_settings.rb +102 -0
- data/app/controllers/concerns/collavre/users_controller/registration.rb +63 -0
- data/app/helpers/collavre/application_helper.rb +1 -0
- data/app/helpers/collavre/creatives_helper.rb +12 -9
- data/app/helpers/collavre/navigation_helper.rb +1 -1
- data/app/javascript/collavre.js +0 -1
- data/app/javascript/controllers/comment_controller.js +33 -70
- data/app/javascript/controllers/comment_version_controller.js +164 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_review.test.js +305 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_selection.test.js +103 -0
- data/app/javascript/controllers/comments/__tests__/review_quotes_store.test.js +113 -0
- data/app/javascript/controllers/comments/contexts_controller.js +363 -0
- data/app/javascript/controllers/comments/form_controller.js +304 -13
- data/app/javascript/controllers/comments/list_controller.js +151 -62
- data/app/javascript/controllers/comments/popup_controller.js +66 -38
- data/app/javascript/controllers/comments/presence_controller.js +2 -10
- data/app/javascript/controllers/comments/review_quotes_store.js +189 -0
- data/app/javascript/controllers/comments/topics_controller.js +34 -10
- data/app/javascript/controllers/index.js +15 -1
- data/app/javascript/controllers/org_chart_controller.js +46 -0
- data/app/javascript/controllers/share_modal_controller.js +369 -0
- data/app/javascript/controllers/topic_search_controller.js +103 -0
- data/app/javascript/creatives/drag_drop/event_handlers.js +42 -1
- data/app/javascript/lib/api/creatives.js +12 -0
- data/app/javascript/lib/api/csrf_fetch.js +35 -0
- data/app/javascript/lib/api/drag_drop.js +17 -0
- data/app/javascript/modules/command_menu.js +40 -0
- data/app/javascript/modules/creative_row_editor.js +88 -0
- data/app/javascript/modules/slide_view.js +2 -1
- data/app/jobs/collavre/ai_agent_job.rb +42 -30
- data/app/jobs/collavre/compress_job.rb +92 -0
- data/app/models/collavre/comment.rb +36 -1
- data/app/models/collavre/comment_version.rb +15 -0
- data/app/models/collavre/creative/describable.rb +1 -1
- data/app/models/collavre/creative.rb +51 -0
- data/app/models/collavre/task.rb +30 -2
- data/app/models/collavre/user.rb +20 -3
- data/app/services/collavre/ai_agent/a2a_dispatcher.rb +68 -0
- data/app/services/collavre/ai_agent/agent_lifecycle_manager.rb +89 -0
- data/app/services/collavre/ai_agent/message_builder.rb +85 -6
- data/app/services/collavre/ai_agent/response_finalizer.rb +97 -0
- data/app/services/collavre/ai_agent/response_streamer.rb +56 -0
- data/app/services/collavre/ai_agent/review_handler.rb +18 -1
- data/app/services/collavre/ai_agent_service.rb +130 -183
- data/app/services/collavre/ai_client.rb +6 -0
- data/app/services/collavre/auto_theme_generator.rb +1 -1
- data/app/services/collavre/command_menu_service.rb +19 -0
- data/app/services/collavre/comments/command_processor.rb +3 -1
- data/app/services/collavre/comments/compress_command.rb +75 -0
- data/app/services/collavre/comments/concerns/workflow_support.rb +115 -0
- data/app/services/collavre/comments/work_command.rb +161 -0
- data/app/services/collavre/comments/workflow_executor.rb +276 -0
- data/app/services/collavre/creatives/plan_tagger.rb +14 -3
- data/app/services/collavre/creatives/tree_formatter.rb +53 -13
- data/app/services/collavre/gemini_parent_recommender.rb +4 -4
- data/app/services/collavre/orchestration/agent_context_builder.rb +1 -3
- data/app/services/collavre/orchestration/agent_orchestrator.rb +15 -4
- data/app/services/collavre/orchestration/policy_resolver.rb +0 -19
- data/app/services/collavre/orchestration/scheduler.rb +3 -2
- data/app/services/collavre/orchestration/stuck_detector.rb +1 -1
- data/app/services/collavre/system_events/dispatcher.rb +9 -0
- data/app/services/collavre/tools/creative_create_service.rb +1 -8
- data/app/services/collavre/tools/creative_import_service.rb +46 -0
- data/app/services/collavre/tools/creative_retrieval_service.rb +157 -96
- data/app/services/collavre/tools/creative_update_service.rb +1 -8
- data/app/services/collavre/tools/cron_list_service.rb +1 -1
- data/app/services/collavre/tools/description_normalizable.rb +16 -0
- data/app/views/collavre/comments/_comment.html.erb +25 -8
- data/app/views/collavre/comments/_comments_popup.html.erb +32 -5
- data/app/views/collavre/creatives/_inline_edit_form.html.erb +13 -0
- data/app/views/collavre/creatives/_share_button.html.erb +4 -1
- data/app/views/collavre/creatives/_share_modal.html.erb +31 -1
- data/app/views/collavre/creatives/index.html.erb +5 -5
- data/app/views/collavre/creatives/slide_view.html.erb +1 -1
- data/app/views/collavre/users/{_contact_management.html.erb → _contact_list.html.erb} +4 -8
- data/app/views/collavre/users/_org_chart.html.erb +68 -0
- data/app/views/collavre/users/_org_chart_node.html.erb +169 -0
- data/app/views/collavre/users/new_ai.html.erb +9 -0
- data/app/views/collavre/users/show.html.erb +32 -8
- data/config/locales/comments.en.yml +57 -2
- data/config/locales/comments.ko.yml +57 -2
- data/config/locales/contacts.en.yml +31 -0
- data/config/locales/contacts.ko.yml +31 -0
- data/config/locales/contexts.en.yml +8 -0
- data/config/locales/contexts.ko.yml +8 -0
- data/config/locales/creatives.en.yml +6 -0
- data/config/locales/creatives.ko.yml +6 -0
- data/config/locales/users.en.yml +1 -0
- data/config/locales/users.ko.yml +1 -0
- data/config/routes.rb +14 -1
- data/db/migrate/20260220072200_add_workflow_fields_to_tasks.rb +12 -0
- data/db/migrate/20260223173533_add_review_type_to_comments.rb +5 -0
- data/db/migrate/20260225065200_create_comment_versions.rb +14 -0
- data/db/migrate/20260225074416_add_selected_version_id_to_comments.rb +7 -0
- data/lib/collavre/version.rb +1 -1
- metadata +47 -10
- data/app/javascript/lib/lexical/__tests__/action_text_attachment_node.test.jsx +0 -91
- data/app/javascript/lib/lexical/action_text_attachment_node.js +0 -459
- data/app/javascript/lib/lexical/dom_attachment_utils.js +0 -66
- data/app/javascript/modules/share_modal.js +0 -76
- data/app/javascript/modules/share_user_popup.js +0 -77
- data/app/services/collavre/orchestration/self_reflection_evaluator.rb +0 -231
- data/app/views/collavre/comments/_presence_avatars.html.erb +0 -8
- data/app/views/collavre/creatives/_delete_button.html.erb +0 -12
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- Share Creative Modal -->
|
|
2
|
-
<div id="share-creative-modal" style="display:none;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:10000;align-items:center;justify-content:center;" data-creative-id="<%= (@parent_creative || @creative).id %>">
|
|
2
|
+
<div id="share-creative-modal" style="display:none;position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:10000;align-items:center;justify-content:center;" data-creative-id="<%= (@parent_creative || @creative).id %>" data-error-message="<%= t('collavre.creatives.share.network_error') %>">
|
|
3
3
|
<div class="popup-box" style="min-width:320px;max-width:90vw;">
|
|
4
4
|
<button type="button" id="close-share-modal" class="popup-close-btn">×</button>
|
|
5
5
|
<h2><%= t('collavre.creatives.index.share_creative') %></h2>
|
|
@@ -48,5 +48,35 @@
|
|
|
48
48
|
</ul>
|
|
49
49
|
</div>
|
|
50
50
|
<% end %>
|
|
51
|
+
<% if defined?(@pending_invitations) && @pending_invitations.any? %>
|
|
52
|
+
<div style="margin-top:1em;">
|
|
53
|
+
<strong><%= t('collavre.contacts.org_chart.pending_invitations') %>:</strong>
|
|
54
|
+
<ul class="share-grid">
|
|
55
|
+
<% @pending_invitations.each do |invitation| %>
|
|
56
|
+
<li>
|
|
57
|
+
<span>
|
|
58
|
+
<div class="avatar-wrapper" style="width: 20px; height: 20px; display: inline-block;">
|
|
59
|
+
<% if invitation.email.present? %>
|
|
60
|
+
<%= image_tag asset_path("default_avatar.svg"),
|
|
61
|
+
alt: '', width: 20, height: 20,
|
|
62
|
+
class: 'avatar share-avatar',
|
|
63
|
+
title: invitation.email,
|
|
64
|
+
style: 'border-radius:50%;vertical-align:middle;' %>
|
|
65
|
+
<span class="avatar-initial" style="font-size: 10px;"><%= invitation.email[0]&.upcase %></span>
|
|
66
|
+
<% else %>
|
|
67
|
+
<span class="avatar share-avatar" style="display:inline-block;width:20px;height:20px;border-radius:50%;background:var(--surface-3,#ddd);text-align:center;line-height:20px;font-size:10px;">🔗</span>
|
|
68
|
+
<% end %>
|
|
69
|
+
</div>
|
|
70
|
+
</span>
|
|
71
|
+
<span><%= invitation.email.presence || t('collavre.creatives.share.public_invite') %></span>
|
|
72
|
+
<span><%= t("collavre.creatives.index.permission_#{invitation.permission}") %></span>
|
|
73
|
+
<span>
|
|
74
|
+
<%= button_to '×', collavre.creative_invitation_path(@parent_creative || @creative, invitation), method: :delete, form: { data: { turbo_confirm: t('collavre.contacts.org_chart.cancel_invite_confirm', email: invitation.email.presence || t('collavre.creatives.share.public_invite')) } }, class: 'delete-share-btn' %>
|
|
75
|
+
</span>
|
|
76
|
+
</li>
|
|
77
|
+
<% end %>
|
|
78
|
+
</ul>
|
|
79
|
+
</div>
|
|
80
|
+
<% end %>
|
|
51
81
|
</div>
|
|
52
82
|
</div>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<%= tag.div(flash[:alert], class: "flash-alert") if flash[:alert] %>
|
|
2
2
|
|
|
3
|
-
<div data-controller="creatives--import creatives--select-mode creatives--drag-drop creatives--expansion creatives--row-editor creatives--set-plan-modal"
|
|
3
|
+
<div data-controller="creatives--import creatives--select-mode creatives--drag-drop creatives--expansion creatives--row-editor creatives--set-plan-modal share-modal"
|
|
4
4
|
data-creatives--import-parent-id-value="<%= @parent_creative&.id %>"
|
|
5
5
|
data-creatives--import-uploading-value="<%= t('collavre.creatives.index.import_uploading') %>"
|
|
6
6
|
data-creatives--import-success-value="<%= t('collavre.creatives.index.import_success') %>"
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
<%= render 'mobile_actions_menu', current_creative: current_creative, can_manage_integrations: can_manage_integrations %>
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
|
-
<% if (@parent_creative || @creative) && (@parent_creative || @creative).has_permission?(Current.user, :write) %>
|
|
65
|
-
|
|
66
|
-
<% end %>
|
|
64
|
+
<% if (@parent_creative || @creative) && (@parent_creative || @creative).has_permission?(Current.user, :write) %>
|
|
65
|
+
<div data-share-modal-target="container"></div>
|
|
66
|
+
<% end %>
|
|
67
67
|
|
|
68
68
|
<%= render 'import_upload_zone' %>
|
|
69
69
|
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
end +
|
|
152
152
|
content_tag(:template, data: { part: "progress" }) do
|
|
153
153
|
if @overall_progress.nil?
|
|
154
|
-
|
|
154
|
+
safe_join([])
|
|
155
155
|
else
|
|
156
156
|
render_progress_value(@overall_progress)
|
|
157
157
|
end
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<% initial_index = params[:slide].to_i.clamp(0, @slide_ids.length - 1) %>
|
|
9
9
|
<% initial_prompt = @creative.prompt_for(Current.user) %>
|
|
10
10
|
<div id="slide-view" data-slide-ids="<%= @slide_ids.join(',') %>" data-initial-index="<%= initial_index %>" data-root-id="<%= @creative.id %>">
|
|
11
|
-
<div id="slide-content"><%= content_tag(tag_name, @creative.effective_description.
|
|
11
|
+
<div id="slide-content"><%= content_tag(tag_name, sanitize(@creative.effective_description, tags: Rails::HTML5::SafeListSanitizer.allowed_tags.to_a + %w[table thead tbody tfoot tr th td], attributes: Rails::HTML5::SafeListSanitizer.allowed_attributes.to_a + %w[colspan rowspan data-lexical])) %></div>
|
|
12
12
|
</div>
|
|
13
13
|
<div id="slide-controls">
|
|
14
14
|
<div id="slide-counter"><%= initial_index + 1 %> / <%= @slide_ids.length %></div>
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
<div class="contact-management">
|
|
2
|
-
|
|
3
|
-
<p class="text-muted"><%= t('collavre.contacts.description') %></p>
|
|
4
|
-
<%= link_to t('collavre.users.add_ai_user'), collavre.new_ai_users_path, class: "primary-action-button" %>
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
|
-
<% show_actions = (contacts || []).any? { |c| c.contact_user.ai_user? && c.contact_user.created_by_id == Current.user.id } %>
|
|
2
|
+
<% show_actions = (contacts || []).any? { |c| c.contact_user&.ai_user? && c.contact_user&.created_by_id == Current.user.id } %>
|
|
8
3
|
|
|
9
4
|
<% if contacts.present? %>
|
|
10
5
|
<div class="table-scroll">
|
|
@@ -24,6 +19,7 @@
|
|
|
24
19
|
<tbody>
|
|
25
20
|
<% contacts.each do |contact| %>
|
|
26
21
|
<% contact_user = contact.contact_user %>
|
|
22
|
+
<% next unless contact_user %>
|
|
27
23
|
<tr>
|
|
28
24
|
<td>
|
|
29
25
|
<%= render Collavre::AvatarComponent.new(
|
|
@@ -67,11 +63,11 @@
|
|
|
67
63
|
<% prev_page = contact_page.to_i - 1 %>
|
|
68
64
|
<% next_page = contact_page.to_i + 1 %>
|
|
69
65
|
<% if contact_page.to_i > 1 %>
|
|
70
|
-
<%= link_to t('collavre.contacts.pagination.prev'), collavre.user_path(Current.user, tab: 'contacts', contact_page: prev_page), class: 'pagination-button' %>
|
|
66
|
+
<%= link_to t('collavre.contacts.pagination.prev'), collavre.user_path(Current.user, tab: 'contacts', contacts_view: 'list', contact_page: prev_page), class: 'pagination-button' %>
|
|
71
67
|
<% end %>
|
|
72
68
|
<span class="pagination-status"><%= t('collavre.contacts.pagination.page_info', current: contact_page, total: total_contact_pages) %></span>
|
|
73
69
|
<% if contact_page.to_i < total_contact_pages.to_i %>
|
|
74
|
-
<%= link_to t('collavre.contacts.pagination.next'), collavre.user_path(Current.user, tab: 'contacts', contact_page: next_page), class: 'pagination-button' %>
|
|
70
|
+
<%= link_to t('collavre.contacts.pagination.next'), collavre.user_path(Current.user, tab: 'contacts', contacts_view: 'list', contact_page: next_page), class: 'pagination-button' %>
|
|
75
71
|
<% end %>
|
|
76
72
|
</nav>
|
|
77
73
|
<% end %>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<div class="org-chart" data-controller="org-chart share-modal">
|
|
2
|
+
<%# Container for dynamically loaded share modal %>
|
|
3
|
+
<div data-share-modal-target="container"></div>
|
|
4
|
+
|
|
5
|
+
<% if org_chart_roots.present? %>
|
|
6
|
+
<div class="org-chart-toolbar">
|
|
7
|
+
<button type="button" class="btn btn-xs btn-secondary"
|
|
8
|
+
data-action="click->org-chart#toggleAll"
|
|
9
|
+
data-org-chart-target="toggleAllBtn"
|
|
10
|
+
data-expand-text="<%= t('collavre.contacts.org_chart.expand_all') %>"
|
|
11
|
+
data-collapse-text="<%= t('collavre.contacts.org_chart.collapse_all') %>">
|
|
12
|
+
<%= t('collavre.contacts.org_chart.expand_all') %>
|
|
13
|
+
</button>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="org-chart-tree">
|
|
16
|
+
<% org_chart_roots.each do |creative| %>
|
|
17
|
+
<%= render partial: 'collavre/users/org_chart_node', locals: {
|
|
18
|
+
creative: creative,
|
|
19
|
+
org_chart_shares: org_chart_shares,
|
|
20
|
+
org_chart_invitations: org_chart_invitations,
|
|
21
|
+
org_chart_children: org_chart_children,
|
|
22
|
+
depth: 0
|
|
23
|
+
} %>
|
|
24
|
+
<% end %>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
27
|
+
|
|
28
|
+
<% if org_chart_unassigned.present? %>
|
|
29
|
+
<div class="org-chart-unassigned">
|
|
30
|
+
<h3 class="org-chart-unassigned-title"><%= t('collavre.contacts.org_chart.unassigned_users') %></h3>
|
|
31
|
+
<div class="org-chart-members">
|
|
32
|
+
<% org_chart_unassigned.each do |user| %>
|
|
33
|
+
<div class="org-chart-member-row">
|
|
34
|
+
<div class="org-chart-member-info">
|
|
35
|
+
<%= render Collavre::AvatarComponent.new(
|
|
36
|
+
user: user,
|
|
37
|
+
size: 24,
|
|
38
|
+
classes: 'avatar'
|
|
39
|
+
) %>
|
|
40
|
+
<div class="org-chart-member-name-group">
|
|
41
|
+
<%= link_to user.display_name, collavre.user_path(user), class: "org-chart-member-name" %>
|
|
42
|
+
<span class="org-chart-member-email"><%= user.email %></span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="org-chart-member-actions">
|
|
46
|
+
<%= link_to t('collavre.users.edit_ai.link'),
|
|
47
|
+
collavre.edit_ai_user_path(user),
|
|
48
|
+
class: "btn btn-xs btn-secondary" %>
|
|
49
|
+
<%= link_to t('collavre.users.copy_ai.link'),
|
|
50
|
+
collavre.new_ai_users_path(copy_from: user.id),
|
|
51
|
+
class: "btn btn-xs btn-secondary" %>
|
|
52
|
+
<%= button_to t('collavre.users.destroy.delete_ai_user'),
|
|
53
|
+
collavre.user_path(user),
|
|
54
|
+
method: :delete,
|
|
55
|
+
form: { data: { turbo_confirm: t('collavre.users.destroy.confirm_ai') } },
|
|
56
|
+
class: "btn btn-xs btn-danger" %>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<% end %>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<% end %>
|
|
63
|
+
|
|
64
|
+
<% if org_chart_roots.blank? && org_chart_unassigned.blank? %>
|
|
65
|
+
<p class="text-muted"><%= t('collavre.contacts.org_chart.empty_state') %></p>
|
|
66
|
+
<% end %>
|
|
67
|
+
|
|
68
|
+
</div>
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<% effective = creative.origin_id? ? creative.effective_origin : creative %>
|
|
2
|
+
<% shares = org_chart_shares.fetch(effective.id, []) %>
|
|
3
|
+
<% invitations = org_chart_invitations.fetch(effective.id, []) %>
|
|
4
|
+
<% children = org_chart_children.fetch(creative.id, []) %>
|
|
5
|
+
<% has_content = shares.any? || invitations.any? || children.any? %>
|
|
6
|
+
<% is_admin = effective.user_id == Current.user.id || shares.any? { |s| s.user_id == Current.user.id && s.permission == "admin" } %>
|
|
7
|
+
|
|
8
|
+
<details class="org-chart-group" <%= 'open' if depth == 0 %>>
|
|
9
|
+
<summary class="org-chart-creative-row <%= 'org-chart-depth-0' if depth == 0 %>" style="--depth: <%= depth %>">
|
|
10
|
+
<span class="org-chart-creative-icon"><%= depth == 0 ? '📂' : '📁' %></span>
|
|
11
|
+
<%= link_to strip_tags(creative.effective_description.to_s).truncate(60),
|
|
12
|
+
collavre.creative_path(creative),
|
|
13
|
+
class: "org-chart-creative-link" %>
|
|
14
|
+
<% if effective.user_id == Current.user.id %>
|
|
15
|
+
<span class="org-chart-owner-badge"><%= t('collavre.contacts.org_chart.owner') %></span>
|
|
16
|
+
<% else %>
|
|
17
|
+
<% my_share = shares.find { |s| s.user_id == Current.user.id } %>
|
|
18
|
+
<% if my_share&.shared_by %>
|
|
19
|
+
<span class="org-chart-direction org-chart-direction-incoming">
|
|
20
|
+
<%= t('collavre.contacts.org_chart.shared_by_user', user: my_share.shared_by.display_name) %>
|
|
21
|
+
</span>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% if is_admin %>
|
|
25
|
+
<button type="button"
|
|
26
|
+
class="btn btn-xs btn-secondary org-chart-manage-btn"
|
|
27
|
+
data-share-modal-url-param="<%= collavre.creative_creative_shares_path(effective) %>"
|
|
28
|
+
data-action="click->share-modal#open">
|
|
29
|
+
<%= t('collavre.contacts.org_chart.manage_permissions') %>
|
|
30
|
+
</button>
|
|
31
|
+
<%= link_to t('collavre.contacts.org_chart.add_ai_agent'),
|
|
32
|
+
collavre.new_ai_users_path(creative_id: effective.id),
|
|
33
|
+
class: "btn btn-xs btn-secondary org-chart-manage-btn" %>
|
|
34
|
+
<% end %>
|
|
35
|
+
</summary>
|
|
36
|
+
|
|
37
|
+
<div class="org-chart-content">
|
|
38
|
+
<% if shares.any? %>
|
|
39
|
+
<div class="org-chart-members" style="--indent: <%= depth %>">
|
|
40
|
+
<% shares.sort_by { |s| Collavre::CreativeShare.permissions[s.permission] }.reverse.each do |share| %>
|
|
41
|
+
<% next unless share.user %>
|
|
42
|
+
<div class="org-chart-member-row">
|
|
43
|
+
<%# Column 1: User info %>
|
|
44
|
+
<div class="org-chart-member-info">
|
|
45
|
+
<%= render Collavre::AvatarComponent.new(
|
|
46
|
+
user: share.user,
|
|
47
|
+
size: 24,
|
|
48
|
+
classes: "avatar org-chart-avatar"
|
|
49
|
+
) %>
|
|
50
|
+
<div class="org-chart-member-name-group">
|
|
51
|
+
<%= link_to share.user.display_name, collavre.user_path(share.user), class: "org-chart-member-name" %>
|
|
52
|
+
<span class="org-chart-member-email"><%= share.user.email %></span>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<%# Column 2: Permission %>
|
|
57
|
+
<div class="org-chart-member-permission">
|
|
58
|
+
<% if is_admin %>
|
|
59
|
+
<select class="org-chart-permission-select org-chart-permission-<%= share.permission %>"
|
|
60
|
+
data-share-id="<%= share.id %>"
|
|
61
|
+
data-update-url="<%= collavre.creative_creative_share_path(effective, share) %>"
|
|
62
|
+
data-action="change->org-chart#updatePermission">
|
|
63
|
+
<% %w[admin write feedback read no_access].each do |perm| %>
|
|
64
|
+
<option value="<%= perm %>" <%= 'selected' if share.permission == perm %>>
|
|
65
|
+
<%= t("collavre.contacts.org_chart.permissions.#{perm}") %>
|
|
66
|
+
</option>
|
|
67
|
+
<% end %>
|
|
68
|
+
</select>
|
|
69
|
+
<% else %>
|
|
70
|
+
<span class="org-chart-permission-badge org-chart-permission-<%= share.permission %>">
|
|
71
|
+
<%= t("collavre.contacts.org_chart.permissions.#{share.permission}") %>
|
|
72
|
+
</span>
|
|
73
|
+
<% end %>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<%# Column 3: Actions %>
|
|
77
|
+
<div class="org-chart-member-actions">
|
|
78
|
+
<% if share.user.ai_user? && share.user.created_by_id == Current.user.id %>
|
|
79
|
+
<%= link_to t('collavre.users.edit_ai.link'), collavre.edit_ai_user_path(share.user), class: "btn btn-xs btn-secondary" %>
|
|
80
|
+
<%= link_to t('collavre.users.copy_ai.link'), collavre.new_ai_users_path(copy_from: share.user.id), class: "btn btn-xs btn-secondary" %>
|
|
81
|
+
<%= button_to t('collavre.users.destroy.delete_ai_user'),
|
|
82
|
+
collavre.user_path(share.user),
|
|
83
|
+
method: :delete,
|
|
84
|
+
form: { data: { turbo_confirm: t('collavre.users.destroy.confirm_ai') } },
|
|
85
|
+
class: "btn btn-xs btn-danger" %>
|
|
86
|
+
<% end %>
|
|
87
|
+
<%= link_to t('collavre.contacts.org_chart.view_profile'), collavre.user_path(share.user), class: "btn btn-xs btn-secondary" %>
|
|
88
|
+
<% if is_admin %>
|
|
89
|
+
<%= button_to t('collavre.contacts.org_chart.unshare'),
|
|
90
|
+
collavre.creative_creative_share_path(effective, share),
|
|
91
|
+
method: :delete,
|
|
92
|
+
form: { data: { turbo_confirm: t('collavre.contacts.org_chart.unshare_confirm', user: share.user.display_name) } },
|
|
93
|
+
class: "btn btn-xs btn-danger" %>
|
|
94
|
+
<% end %>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
<% end %>
|
|
98
|
+
</div>
|
|
99
|
+
<% end %>
|
|
100
|
+
|
|
101
|
+
<% if invitations.any? && is_admin %>
|
|
102
|
+
<div class="org-chart-members" style="--indent: <%= depth %>">
|
|
103
|
+
<% invitations.each do |invitation| %>
|
|
104
|
+
<div class="org-chart-member-row org-chart-invitation-row">
|
|
105
|
+
<%# Column 1: Invitation info %>
|
|
106
|
+
<div class="org-chart-member-info">
|
|
107
|
+
<div class="avatar-wrapper" style="width: 24px; height: 24px;">
|
|
108
|
+
<% if invitation.email.present? %>
|
|
109
|
+
<%= image_tag asset_path("default_avatar.svg"),
|
|
110
|
+
alt: '', width: 24, height: 24,
|
|
111
|
+
class: 'avatar',
|
|
112
|
+
title: invitation.email,
|
|
113
|
+
style: 'border-radius:50%;vertical-align:middle;' %>
|
|
114
|
+
<span class="avatar-initial" style="font-size: 12px;"><%= invitation.email[0]&.upcase %></span>
|
|
115
|
+
<% else %>
|
|
116
|
+
<span class="avatar" style="display:inline-block;width:24px;height:24px;border-radius:50%;background:var(--surface-3,#ddd);text-align:center;line-height:24px;font-size:12px;">🔗</span>
|
|
117
|
+
<% end %>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="org-chart-member-name-group">
|
|
120
|
+
<span class="org-chart-member-email"><%= invitation.email.presence || t('collavre.creatives.share.public_invite') %></span>
|
|
121
|
+
<span class="org-chart-pending-badge"><%= t('collavre.contacts.org_chart.pending_status') %></span>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<%# Column 2: Permission %>
|
|
126
|
+
<div class="org-chart-member-permission">
|
|
127
|
+
<select class="org-chart-permission-select org-chart-permission-<%= invitation.permission %>"
|
|
128
|
+
data-update-url="<%= collavre.creative_invitation_path(effective, invitation) %>"
|
|
129
|
+
data-action="change->org-chart#updatePermission">
|
|
130
|
+
<% %w[admin write feedback read no_access].each do |perm| %>
|
|
131
|
+
<option value="<%= perm %>" <%= 'selected' if invitation.permission == perm %>>
|
|
132
|
+
<%= t("collavre.contacts.org_chart.permissions.#{perm}") %>
|
|
133
|
+
</option>
|
|
134
|
+
<% end %>
|
|
135
|
+
</select>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<%# Column 3: Actions %>
|
|
139
|
+
<div class="org-chart-member-actions">
|
|
140
|
+
<%= button_to t('collavre.contacts.org_chart.cancel_invite'),
|
|
141
|
+
collavre.creative_invitation_path(effective, invitation),
|
|
142
|
+
method: :delete,
|
|
143
|
+
form: { data: { turbo_confirm: t('collavre.contacts.org_chart.cancel_invite_confirm', email: invitation.email.presence || t('collavre.creatives.share.public_invite')) } },
|
|
144
|
+
class: "btn btn-xs btn-danger" %>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<% end %>
|
|
148
|
+
</div>
|
|
149
|
+
<% end %>
|
|
150
|
+
|
|
151
|
+
<% if children.any? %>
|
|
152
|
+
<div class="org-chart-children" style="--indent: <%= depth %>">
|
|
153
|
+
<% children.each do |child| %>
|
|
154
|
+
<%= render partial: 'collavre/users/org_chart_node', locals: {
|
|
155
|
+
creative: child,
|
|
156
|
+
org_chart_shares: org_chart_shares,
|
|
157
|
+
org_chart_invitations: org_chart_invitations,
|
|
158
|
+
org_chart_children: org_chart_children,
|
|
159
|
+
depth: depth + 1
|
|
160
|
+
} %>
|
|
161
|
+
<% end %>
|
|
162
|
+
</div>
|
|
163
|
+
<% end %>
|
|
164
|
+
|
|
165
|
+
<% unless has_content %>
|
|
166
|
+
<p class="org-chart-no-members" style="--indent: <%= depth %>"><%= t('collavre.contacts.org_chart.no_members') %></p>
|
|
167
|
+
<% end %>
|
|
168
|
+
</div>
|
|
169
|
+
</details>
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
<h1 class="text-center" style="margin-top: 0;"><%= t('collavre.users.new_ai.title') %></h1>
|
|
3
3
|
|
|
4
4
|
<%= form_with url: collavre.create_ai_users_path, class: "stacked-form" do |form| %>
|
|
5
|
+
<% if params[:creative_id].present? %>
|
|
6
|
+
<%= form.hidden_field :creative_id, value: params[:creative_id] %>
|
|
7
|
+
<% creative = Collavre::Creative.find_by(id: params[:creative_id]) %>
|
|
8
|
+
<% if creative %>
|
|
9
|
+
<div class="form-group">
|
|
10
|
+
<p class="text-muted"><%= t('collavre.contacts.org_chart.add_ai_agent_to', creative: creative.plain_description) %></p>
|
|
11
|
+
</div>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
5
14
|
<div class="form-group">
|
|
6
15
|
<%= form.label :ai_id, t('collavre.users.new_ai.id_label') %>
|
|
7
16
|
<%= form.text_field :ai_id, required: true, class: "stacked-form-control", placeholder: "e.g. my_bot", value: @copy_source ? "#{@copy_source.email.split('@').first}_copy" : nil %>
|
|
@@ -130,14 +130,38 @@
|
|
|
130
130
|
</section>
|
|
131
131
|
|
|
132
132
|
<section class="tab-panel <%= 'active' if active_tab == 'contacts' %>" data-tabs-target="panel" data-tab-name="contacts">
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
133
|
+
<div class="flex-row-center-between">
|
|
134
|
+
<div class="contacts-view-switcher">
|
|
135
|
+
<%= link_to t('collavre.contacts.views.list'),
|
|
136
|
+
collavre.user_path(Current.user, tab: 'contacts', contacts_view: 'list'),
|
|
137
|
+
class: "btn btn-xs #{@contacts_view == 'list' ? 'btn-primary' : 'btn-secondary'}" %>
|
|
138
|
+
<%= link_to t('collavre.contacts.views.org_chart'),
|
|
139
|
+
collavre.user_path(Current.user, tab: 'contacts', contacts_view: 'org_chart'),
|
|
140
|
+
class: "btn btn-xs #{@contacts_view == 'org_chart' ? 'btn-primary' : 'btn-secondary'}" %>
|
|
141
|
+
</div>
|
|
142
|
+
<div>
|
|
143
|
+
<p class="text-muted contacts-description"><%= t('collavre.contacts.description') %></p>
|
|
144
|
+
<%= link_to t('collavre.users.add_ai_user'), collavre.new_ai_users_path, class: "primary-action-button" %>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<% if @contacts_view == 'org_chart' %>
|
|
149
|
+
<%= render partial: 'collavre/users/org_chart', locals: {
|
|
150
|
+
org_chart_roots: @org_chart_roots,
|
|
151
|
+
org_chart_shares: @org_chart_shares,
|
|
152
|
+
org_chart_invitations: @org_chart_invitations,
|
|
153
|
+
org_chart_children: @org_chart_children,
|
|
154
|
+
org_chart_unassigned: @org_chart_unassigned
|
|
155
|
+
} %>
|
|
156
|
+
<% else %>
|
|
157
|
+
<%= render partial: 'collavre/users/contact_list', locals: {
|
|
158
|
+
contacts: @contacts,
|
|
159
|
+
shared_by_me: @shared_by_me,
|
|
160
|
+
shared_with_me: @shared_with_me,
|
|
161
|
+
contact_page: @contact_page,
|
|
162
|
+
total_contact_pages: @total_contact_pages
|
|
163
|
+
} %>
|
|
164
|
+
<% end %>
|
|
141
165
|
</section>
|
|
142
166
|
</div>
|
|
143
167
|
</div>
|
|
@@ -5,6 +5,9 @@ en:
|
|
|
5
5
|
delete_confirm: This will delete all messages in this topic. Are you sure?
|
|
6
6
|
new_placeholder: New Topic
|
|
7
7
|
no_permission: You don't have permission to perform this action.
|
|
8
|
+
move:
|
|
9
|
+
no_target_permission: You don't have write permission on the target creative.
|
|
10
|
+
duplicate_name: A topic named '%{name}' already exists in the target creative.
|
|
8
11
|
github_auth:
|
|
9
12
|
login_first: Please sign in first.
|
|
10
13
|
connected: Github account connected successfully.
|
|
@@ -66,12 +69,29 @@ en:
|
|
|
66
69
|
speech_unavailable: Speech recognition is not supported in this browser.
|
|
67
70
|
move_button: Move
|
|
68
71
|
review_button: Review
|
|
72
|
+
review_select_hint: Please select text to review
|
|
73
|
+
review_feedback_placeholder: Write feedback for this quote...
|
|
74
|
+
review_summary_placeholder: Overall comment (optional)...
|
|
75
|
+
review_add_quote: "+ Add"
|
|
76
|
+
review_send: Send review
|
|
77
|
+
review_send_question: Send question
|
|
78
|
+
review_type_review: Review
|
|
79
|
+
review_type_question: Question
|
|
69
80
|
replace_button: Replace
|
|
70
81
|
move_no_selection: Select at least one message to move.
|
|
71
82
|
move_error: Unable to move messages.
|
|
72
83
|
add_participant: Add user
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
selection_count: "{count} selected"
|
|
85
|
+
selection_delete: Delete
|
|
86
|
+
selection_move: Move
|
|
87
|
+
selection_topic_move: Move to topic
|
|
88
|
+
selection_close: Cancel
|
|
89
|
+
selection_drag_hint: "You can also drag & drop to move to a topic"
|
|
90
|
+
batch_delete_confirm: Are you sure you want to delete the selected messages?
|
|
91
|
+
batch_delete_no_selection: Select at least one message to delete.
|
|
92
|
+
batch_delete_not_found: Some selected messages could not be found.
|
|
93
|
+
topic_search_placeholder: Search topics...
|
|
94
|
+
topic_main: Main
|
|
75
95
|
fullscreen: Full screen
|
|
76
96
|
exit_fullscreen: Exit full screen
|
|
77
97
|
move_invalid_target: Select a valid creative to move messages to.
|
|
@@ -85,18 +105,53 @@ en:
|
|
|
85
105
|
calendar_args: "YYYY-MM-DD@HH:MM memo (today/tomorrow, +3days, +2weeks, +1months, +1years, +mon)"
|
|
86
106
|
topic_description: "Create a new topic with optional primary agent."
|
|
87
107
|
topic_args: '"topic name" @agent_name'
|
|
108
|
+
work_description: "Create a workflow to execute tasks on child creatives via DFS traversal."
|
|
109
|
+
work_args: "@agent_name workflow_context"
|
|
110
|
+
compress_description: "Summarize all messages in the current topic and remove originals."
|
|
111
|
+
compress_args: "[additional instructions]"
|
|
112
|
+
creative_description: "Insert a link to a creative. In AI chats, the linked creative tree is injected as context."
|
|
88
113
|
calendar_command:
|
|
89
114
|
event_created: 'event created: [Google Calendar event](%{url})'
|
|
90
115
|
event_created_local: 'event created (local only - connect Google Calendar to sync)'
|
|
91
116
|
event_created_sync_failed: 'event created (Google Calendar sync failed - please reconnect your Google account)'
|
|
92
117
|
mcp_command:
|
|
93
118
|
error_running: "Error running /%{tool_name}: %{error}"
|
|
119
|
+
compress_command:
|
|
120
|
+
not_authorized: "You need write permission to compress a topic."
|
|
121
|
+
topic_required: "The /compress command can only be used within a topic."
|
|
122
|
+
nothing_to_compress: "No messages to compress in this topic."
|
|
123
|
+
started: "⏳ Compressing topic messages..."
|
|
124
|
+
summary_title: "Topic Summary — %{topic}"
|
|
125
|
+
failed: "Compress failed"
|
|
94
126
|
topic_command:
|
|
95
127
|
missing_name: 'Please specify a topic name in quotes: /topic "topic name"'
|
|
96
128
|
created: 'Topic "%{name}" created.'
|
|
97
129
|
created_with_agent: 'Topic "%{name}" created with @%{agent} as primary agent.'
|
|
98
130
|
updated_agent: 'Topic "%{name}" primary agent updated to @%{agent}.'
|
|
99
131
|
already_exists: 'Topic "%{name}" already exists.'
|
|
132
|
+
work_command:
|
|
133
|
+
agent_not_found: "Please mention an AI agent to execute the workflow."
|
|
134
|
+
no_children: "This creative has no child creatives to work on."
|
|
135
|
+
all_already_tasked: "All child creatives already have active tasks."
|
|
136
|
+
started: 'Workflow started with @%{agent}: %{total} tasks queued (%{skipped} skipped).'
|
|
137
|
+
trigger_comment: '📋 [Workflow] %{context}'
|
|
138
|
+
subtask_started: '📋 @%{agent} starting work on "%{creative}" (%{current}/%{total})'
|
|
139
|
+
subtask_completed: '✅ @%{agent} completed "%{creative}" (%{completed}/%{total}, %{progress}%%)'
|
|
140
|
+
workflow_completed: '✅ Workflow completed by @%{agent}: %{completed} creatives processed.'
|
|
141
|
+
workflow_failed: 'Workflow failed by @%{agent} on "%{creative}": %{reason}'
|
|
142
|
+
workflow_stopped: '⏹️ Workflow stopped by @%{agent}. %{completed} completed, %{remaining} remaining.'
|
|
143
|
+
workflow_resumed: '▶️ Workflow resumed by @%{agent}. %{remaining} tasks remaining.'
|
|
144
|
+
stopped: 'Workflow stopped for @%{agent}.'
|
|
145
|
+
resumed: 'Workflow resumed for @%{agent}: %{remaining} tasks remaining.'
|
|
146
|
+
no_active_workflow: 'No active workflow found on this creative.'
|
|
147
|
+
no_resumable_workflow: 'No failed or stopped workflow found to resume.'
|
|
148
|
+
supervisor_instruction: "If you need clarification, have questions, or are unsure about anything, ask @%{supervisor}: instead of the user. They will guide you."
|
|
149
|
+
versions:
|
|
150
|
+
previous: Previous version
|
|
151
|
+
next: Next version
|
|
152
|
+
delete: Delete this version
|
|
153
|
+
delete_confirm: Are you sure you want to delete this version?
|
|
154
|
+
select: Select
|
|
100
155
|
read_by: Read by %{name}
|
|
101
156
|
activity_logs_summary: Activity Logs
|
|
102
157
|
calendar_events:
|
|
@@ -5,6 +5,9 @@ ko:
|
|
|
5
5
|
delete_confirm: 이 토픽의 모든 메시지가 삭제됩니다. 확실합니까?
|
|
6
6
|
new_placeholder: 새 토픽
|
|
7
7
|
no_permission: 이 작업을 수행할 권한이 없습니다.
|
|
8
|
+
move:
|
|
9
|
+
no_target_permission: 대상 크리에이티브에 대한 쓰기 권한이 없습니다.
|
|
10
|
+
duplicate_name: "'%{name}' 토픽이 대상 크리에이티브에 이미 존재합니다."
|
|
8
11
|
github_auth:
|
|
9
12
|
login_first: 먼저 로그인해주세요.
|
|
10
13
|
connected: Github 계정이 연동되었습니다.
|
|
@@ -63,12 +66,29 @@ ko:
|
|
|
63
66
|
speech_unavailable: 이 브라우저는 음성 인식을 지원하지 않습니다.
|
|
64
67
|
move_button: 이동
|
|
65
68
|
review_button: 리뷰
|
|
69
|
+
review_select_hint: 리뷰할 텍스트를 선택해 주세요
|
|
70
|
+
review_feedback_placeholder: 이 인용에 대한 피드백을 입력하세요...
|
|
71
|
+
review_summary_placeholder: 종합 코멘트 (선택)...
|
|
72
|
+
review_add_quote: "+ 추가"
|
|
73
|
+
review_send: 리뷰 전송
|
|
74
|
+
review_send_question: 질문 보내기
|
|
75
|
+
review_type_review: 리뷰
|
|
76
|
+
review_type_question: 질문
|
|
66
77
|
replace_button: 바꾸기
|
|
67
78
|
move_no_selection: 이동할 메시지를 선택해주세요.
|
|
68
79
|
move_error: 메시지를 이동할 수 없습니다.
|
|
69
80
|
add_participant: 사용자 추가
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
selection_count: "{count}개 선택"
|
|
82
|
+
selection_delete: 삭제
|
|
83
|
+
selection_move: 이동
|
|
84
|
+
selection_topic_move: 토픽 이동
|
|
85
|
+
selection_close: 취소
|
|
86
|
+
selection_drag_hint: "드래그&드롭으로도 토픽 이동 가능"
|
|
87
|
+
batch_delete_confirm: 선택한 메시지를 삭제하시겠습니까?
|
|
88
|
+
batch_delete_no_selection: 삭제할 메시지를 선택해주세요.
|
|
89
|
+
batch_delete_not_found: 일부 선택한 메시지를 찾을 수 없습니다.
|
|
90
|
+
topic_search_placeholder: 토픽 검색...
|
|
91
|
+
topic_main: 메인
|
|
72
92
|
fullscreen: 전체 화면
|
|
73
93
|
exit_fullscreen: 전체 화면 종료
|
|
74
94
|
move_invalid_target: 이동할 크리에이티브를 선택해주세요.
|
|
@@ -82,18 +102,53 @@ ko:
|
|
|
82
102
|
calendar_args: "YYYY-MM-DD@HH:MM 메모 (today/tomorrow, +3days, +2weeks, +1months, +1years, +mon/+월)"
|
|
83
103
|
topic_description: "새 토픽을 생성합니다. Primary Agent를 지정할 수 있습니다."
|
|
84
104
|
topic_args: '"토픽 이름" @에이전트이름'
|
|
105
|
+
work_description: "하위 크리에이티브들에 대해 DFS 순회를 통한 워크플로우를 실행합니다."
|
|
106
|
+
work_args: "@에이전트이름 워크플로우_컨텍스트"
|
|
107
|
+
compress_description: "현재 토픽의 모든 메세지를 요약하고 원본을 삭제합니다."
|
|
108
|
+
compress_args: "[추가 지시사항]"
|
|
109
|
+
creative_description: "크리에이티브 링크를 삽입합니다. AI 채팅에서는 링크된 크리에이티브 트리가 컨텍스트로 주입됩니다."
|
|
85
110
|
calendar_command:
|
|
86
111
|
event_created: '이벤트가 생성되었습니다: [구글 캘린더 이벤트](%{url})'
|
|
87
112
|
event_created_local: '이벤트가 생성되었습니다 (로컬 전용 - 구글 캘린더 연동 시 동기화됩니다)'
|
|
88
113
|
event_created_sync_failed: '이벤트가 생성되었습니다 (구글 캘린더 동기화 실패 - 구글 계정을 다시 연동해주세요)'
|
|
89
114
|
mcp_command:
|
|
90
115
|
error_running: "/%{tool_name} 실행 오류: %{error}"
|
|
116
|
+
compress_command:
|
|
117
|
+
not_authorized: "토픽을 요약하려면 쓰기 권한이 필요합니다."
|
|
118
|
+
topic_required: "/compress 명령은 토픽 내에서만 사용할 수 있습니다."
|
|
119
|
+
nothing_to_compress: "이 토픽에 요약할 메세지가 없습니다."
|
|
120
|
+
started: "⏳ 토픽 메세지를 요약하는 중..."
|
|
121
|
+
summary_title: "토픽 요약 — %{topic}"
|
|
122
|
+
failed: "요약 실패"
|
|
91
123
|
topic_command:
|
|
92
124
|
missing_name: '토픽 이름을 따옴표로 지정하세요: /topic "토픽 이름"'
|
|
93
125
|
created: '토픽 "%{name}"이(가) 생성되었습니다.'
|
|
94
126
|
created_with_agent: '토픽 "%{name}"이(가) 생성되었습니다. @%{agent}이(가) Primary Agent로 설정되었습니다.'
|
|
95
127
|
updated_agent: '토픽 "%{name}"의 Primary Agent가 @%{agent}(으)로 변경되었습니다.'
|
|
96
128
|
already_exists: '토픽 "%{name}"이(가) 이미 존재합니다.'
|
|
129
|
+
work_command:
|
|
130
|
+
agent_not_found: "워크플로우를 실행할 AI 에이전트를 멘션해주세요."
|
|
131
|
+
no_children: "이 크리에이티브에는 작업할 하위 크리에이티브가 없습니다."
|
|
132
|
+
all_already_tasked: "모든 하위 크리에이티브가 이미 활성 작업을 가지고 있습니다."
|
|
133
|
+
started: '워크플로우가 @%{agent}와 함께 시작되었습니다: %{total}개 작업 대기중 (%{skipped}개 생략).'
|
|
134
|
+
trigger_comment: '📋 [워크플로우] %{context}'
|
|
135
|
+
subtask_started: '📋 @%{agent}가 "%{creative}" 작업을 시작합니다 (%{current}/%{total})'
|
|
136
|
+
subtask_completed: '✅ @%{agent}가 "%{creative}" 완료 (%{completed}/%{total}, %{progress}%%)'
|
|
137
|
+
workflow_completed: '✅ @%{agent}가 워크플로우를 완료했습니다: %{completed}개 크리에이티브 처리됨.'
|
|
138
|
+
workflow_failed: '@%{agent} 워크플로우 실패 - "%{creative}": %{reason}'
|
|
139
|
+
workflow_stopped: '⏹️ @%{agent} 워크플로우가 중지되었습니다. %{completed}개 완료, %{remaining}개 남음.'
|
|
140
|
+
workflow_resumed: '▶️ @%{agent} 워크플로우가 재개되었습니다. %{remaining}개 작업 남음.'
|
|
141
|
+
stopped: '@%{agent}의 워크플로우가 중지되었습니다.'
|
|
142
|
+
resumed: '@%{agent}의 워크플로우가 재개되었습니다: %{remaining}개 작업 남음.'
|
|
143
|
+
no_active_workflow: '이 크리에이티브에 활성 워크플로우가 없습니다.'
|
|
144
|
+
no_resumable_workflow: '재개할 수 있는 실패/중지된 워크플로우가 없습니다.'
|
|
145
|
+
supervisor_instruction: "질문이 있거나 확인이 필요하면 사용자 대신 @%{supervisor}: 에게 물어보세요. 감독자가 안내해줄 것입니다."
|
|
146
|
+
versions:
|
|
147
|
+
previous: 이전 버전
|
|
148
|
+
next: 다음 버전
|
|
149
|
+
delete: 이 버전 삭제
|
|
150
|
+
delete_confirm: 이 버전을 삭제하시겠습니까?
|
|
151
|
+
select: 선택
|
|
97
152
|
read_by: "%{name} 님이 읽음"
|
|
98
153
|
activity_logs_summary: 활동 기록
|
|
99
154
|
calendar_events:
|