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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/collavre/comments_popup.css +293 -8
  3. data/app/assets/stylesheets/collavre/mention_menu.css +26 -0
  4. data/app/assets/stylesheets/collavre/popup.css +7 -0
  5. data/app/assets/stylesheets/collavre/print.css +18 -0
  6. data/app/channels/collavre/comments_presence_channel.rb +33 -0
  7. data/app/components/collavre/autocomplete_popup_component.html.erb +3 -0
  8. data/app/components/collavre/autocomplete_popup_component.rb +18 -0
  9. data/app/components/collavre/command_menu_component.rb +7 -0
  10. data/app/components/collavre/plans_timeline_component.html.erb +1 -1
  11. data/app/components/collavre/plans_timeline_component.rb +29 -32
  12. data/app/components/collavre/user_mention_menu_component.rb +4 -5
  13. data/app/controllers/collavre/comments_controller.rb +111 -10
  14. data/app/controllers/collavre/creatives_controller.rb +8 -0
  15. data/app/controllers/collavre/google_auth_controller.rb +5 -1
  16. data/app/controllers/collavre/plans_controller.rb +65 -9
  17. data/app/controllers/collavre/topics_controller.rb +42 -0
  18. data/app/controllers/collavre/users_controller.rb +4 -14
  19. data/app/errors/collavre/approval_pending_error.rb +54 -0
  20. data/app/errors/collavre/cancelled_error.rb +9 -0
  21. data/app/helpers/collavre/navigation_helper.rb +3 -1
  22. data/app/javascript/collavre.js +1 -0
  23. data/app/javascript/controllers/comments/__tests__/popup_controller.test.js +2 -1
  24. data/app/javascript/controllers/comments/form_controller.js +2 -1
  25. data/app/javascript/controllers/comments/list_controller.js +185 -2
  26. data/app/javascript/controllers/comments/popup_controller.js +95 -20
  27. data/app/javascript/controllers/comments/presence_controller.js +30 -1
  28. data/app/javascript/controllers/comments/topics_controller.js +314 -4
  29. data/app/javascript/modules/__tests__/creative_progress.test.js +50 -0
  30. data/app/javascript/modules/command_menu.js +116 -0
  31. data/app/javascript/modules/creative_progress.js +14 -0
  32. data/app/javascript/modules/creative_row_editor.js +104 -20
  33. data/app/javascript/modules/plans_timeline.js +15 -4
  34. data/app/javascript/modules/share_modal.js +3 -0
  35. data/app/jobs/collavre/ai_agent_job.rb +35 -21
  36. data/app/models/collavre/calendar_event.rb +7 -1
  37. data/app/models/collavre/comment.rb +35 -2
  38. data/app/models/collavre/creative.rb +1 -3
  39. data/app/models/collavre/mcp_tool.rb +4 -0
  40. data/app/models/collavre/plan.rb +23 -0
  41. data/app/models/collavre/topic.rb +12 -0
  42. data/app/models/collavre/user.rb +15 -1
  43. data/app/services/collavre/ai_agent_service.rb +174 -66
  44. data/app/services/collavre/ai_client.rb +31 -2
  45. data/app/services/collavre/comments/action_executor.rb +47 -1
  46. data/app/services/collavre/comments/calendar_command.rb +117 -18
  47. data/app/services/collavre/google_calendar_service.rb +38 -15
  48. data/app/services/collavre/markdown_importer.rb +47 -8
  49. data/app/services/collavre/mcp_service.rb +23 -10
  50. data/app/services/collavre/system_events/router.rb +50 -26
  51. data/app/services/collavre/tools/creative_create_service.rb +97 -0
  52. data/app/services/collavre/tools/creative_update_service.rb +116 -0
  53. data/app/views/collavre/comments/_comment.html.erb +2 -2
  54. data/app/views/collavre/comments/_comments_popup.html.erb +40 -6
  55. data/app/views/collavre/comments/fullscreen.html.erb +5 -0
  56. data/app/views/collavre/creatives/_inline_edit_form.html.erb +11 -3
  57. data/app/views/collavre/creatives/_integration_modals.html.erb +6 -0
  58. data/app/views/collavre/creatives/_integration_triggers.html.erb +8 -0
  59. data/app/views/collavre/creatives/_integrations_menu.html.erb +12 -0
  60. data/app/views/collavre/creatives/_mobile_actions_menu.html.erb +13 -1
  61. data/app/views/collavre/creatives/_share_button.html.erb +1 -1
  62. data/app/views/collavre/creatives/index.html.erb +22 -4
  63. data/app/views/collavre/users/edit_ai.html.erb +15 -0
  64. data/app/views/collavre/users/new_ai.html.erb +15 -0
  65. data/app/views/layouts/collavre/chat.html.erb +46 -0
  66. data/config/locales/ai_agent.en.yml +15 -0
  67. data/config/locales/ai_agent.ko.yml +15 -0
  68. data/config/locales/comments.en.yml +15 -3
  69. data/config/locales/comments.ko.yml +15 -3
  70. data/config/locales/creatives.en.yml +3 -31
  71. data/config/locales/creatives.ko.yml +3 -27
  72. data/config/locales/plans.en.yml +4 -0
  73. data/config/locales/plans.ko.yml +4 -0
  74. data/config/locales/users.en.yml +3 -0
  75. data/config/locales/users.ko.yml +3 -0
  76. data/config/routes.rb +8 -3
  77. data/db/migrate/20260120045354_encrypt_oauth_tokens.rb +1 -1
  78. data/db/migrate/20260131100000_migrate_active_storage_attachment_record_types.rb +21 -0
  79. data/db/migrate/20260201100000_make_google_event_id_nullable.rb +5 -0
  80. data/lib/collavre/engine.rb +171 -6
  81. data/lib/collavre/integration_registry.rb +129 -0
  82. data/lib/collavre/version.rb +1 -1
  83. data/lib/collavre.rb +2 -0
  84. data/lib/navigation/registry.rb +130 -0
  85. metadata +22 -15
  86. data/app/components/collavre/user_mention_menu_component.html.erb +0 -3
  87. data/app/controllers/collavre/notion_auth_controller.rb +0 -25
  88. data/app/jobs/collavre/notion_export_job.rb +0 -30
  89. data/app/jobs/collavre/notion_sync_job.rb +0 -48
  90. data/app/models/collavre/notion_account.rb +0 -17
  91. data/app/models/collavre/notion_block_link.rb +0 -10
  92. data/app/models/collavre/notion_page_link.rb +0 -19
  93. data/app/services/collavre/notion_client.rb +0 -231
  94. data/app/services/collavre/notion_creative_exporter.rb +0 -296
  95. data/app/services/collavre/notion_service.rb +0 -249
  96. data/app/views/collavre/creatives/_notion_integration_modal.html.erb +0 -90
  97. data/db/migrate/20241201000000_create_notion_integrations.rb +0 -29
  98. data/db/migrate/20250312000000_create_notion_block_links.rb +0 -16
  99. data/db/migrate/20250312010000_allow_multiple_notion_blocks_per_creative.rb +0 -5
@@ -41,12 +41,6 @@ module Collavre
41
41
  end
42
42
  end
43
43
 
44
- # Add engine locales to I18n load path
45
- # Host app can override these translations by defining the same keys
46
- initializer "collavre.i18n" do |app|
47
- config.i18n.load_path += Dir[root.join("config/locales/**/*.yml")]
48
- end
49
-
50
44
  # Allow engine controllers to fall back to host app views during migration
51
45
  # This enables gradual view migration - views can stay in host app until moved to engine
52
46
  initializer "collavre.view_paths" do
@@ -73,5 +67,176 @@ module Collavre
73
67
  end
74
68
  end
75
69
  end
70
+
71
+ # Reset navigation registry before any registrations (runs first)
72
+ initializer "collavre.navigation_reset" do
73
+ ActiveSupport::Reloader.to_prepare(prepend: true) do
74
+ Navigation::Registry.instance.reset!
75
+ end
76
+ end
77
+
78
+ # Register core navigation items
79
+ # Host app or other engines can add/modify items in their own initializers
80
+ initializer "collavre.navigation", after: "collavre.navigation_reset" do
81
+ Rails.application.config.to_prepare do
82
+ # ============================================
83
+ # Search Section
84
+ # ============================================
85
+ Navigation::Registry.instance.register(
86
+ key: :search,
87
+ label: "app.search_placeholder",
88
+ section: :search,
89
+ type: :partial,
90
+ partial: "collavre/shared/navigation/search_form",
91
+ priority: 10
92
+ )
93
+
94
+ # ============================================
95
+ # Main Section - Mobile Only
96
+ # ============================================
97
+ Navigation::Registry.instance.register(
98
+ key: :mobile_plans,
99
+ label: "app.plans",
100
+ type: :partial,
101
+ partial: "collavre/shared/navigation/mobile_plans_button",
102
+ priority: 100,
103
+ requires_auth: true,
104
+ desktop: false,
105
+ mobile: true
106
+ )
107
+
108
+ # ============================================
109
+ # Main Section - Desktop Navigation
110
+ # ============================================
111
+ Navigation::Registry.instance.register(
112
+ key: :home,
113
+ label: "app.home",
114
+ type: :button,
115
+ path: -> { main_app.root_path },
116
+ priority: 110
117
+ )
118
+
119
+ Navigation::Registry.instance.register(
120
+ key: :plans,
121
+ label: "app.plans",
122
+ type: :partial,
123
+ partial: "collavre/shared/navigation/plans_button",
124
+ priority: 120,
125
+ requires_auth: true,
126
+ mobile: false
127
+ )
128
+
129
+ Navigation::Registry.instance.register(
130
+ key: :progress_filter,
131
+ label: "",
132
+ type: :component,
133
+ component: Collavre::ProgressFilterComponent,
134
+ component_args: {
135
+ current_state: -> {
136
+ if params[:min_progress] == "1" && params[:max_progress] == "1"
137
+ :complete
138
+ elsif params[:min_progress] == "0" && params[:max_progress] == "0.99"
139
+ :incomplete
140
+ else
141
+ :all
142
+ end
143
+ },
144
+ states: [
145
+ { name: -> { I18n.t("app.filter_complete") }, value: :complete },
146
+ { name: -> { I18n.t("app.filter_incomplete") }, value: :incomplete },
147
+ { name: -> { I18n.t("app.filter_all") }, value: :all }
148
+ ]
149
+ },
150
+ priority: 130,
151
+ requires_auth: true
152
+ )
153
+
154
+ Navigation::Registry.instance.register(
155
+ key: :comment_filter,
156
+ label: "",
157
+ type: :component,
158
+ component: Collavre::ProgressFilterComponent,
159
+ component_args: {
160
+ current_state: -> { params[:comment] == "true" ? :comment : nil },
161
+ states: [
162
+ { name: -> { I18n.t("app.filter_comments") }, value: :comment }
163
+ ]
164
+ },
165
+ priority: 140,
166
+ requires_auth: true
167
+ )
168
+
169
+ Navigation::Registry.instance.register(
170
+ key: :inbox,
171
+ label: "app.inbox",
172
+ type: :partial,
173
+ partial: "collavre/shared/navigation/inbox_button",
174
+ priority: 150,
175
+ requires_user: true,
176
+ mobile: false
177
+ )
178
+
179
+ Navigation::Registry.instance.register(
180
+ key: :mobile_inbox,
181
+ label: "app.inbox",
182
+ type: :partial,
183
+ partial: "collavre/shared/navigation/mobile_inbox_button",
184
+ priority: 155,
185
+ requires_user: true,
186
+ desktop: false,
187
+ mobile: true
188
+ )
189
+
190
+ Navigation::Registry.instance.register(
191
+ key: :sign_in,
192
+ label: "app.sign_in",
193
+ type: :button,
194
+ path: -> { Collavre::Engine.routes.url_helpers.new_session_path },
195
+ priority: 160,
196
+ visible: -> { !authenticated? }
197
+ )
198
+
199
+ Navigation::Registry.instance.register(
200
+ key: :help,
201
+ label: "?",
202
+ type: :partial,
203
+ partial: "collavre/shared/navigation/help_button",
204
+ priority: 170
205
+ )
206
+
207
+ # ============================================
208
+ # User Section
209
+ # ============================================
210
+ Navigation::Registry.instance.register(
211
+ key: :user_menu,
212
+ label: "",
213
+ section: :user,
214
+ type: :raw,
215
+ button_content: -> { render(AvatarComponent.new(user: Current.user, size: 32, classes: "nav-avatar avatar")) },
216
+ menu_id: "user-menu",
217
+ align: :right,
218
+ priority: 100,
219
+ requires_user: true,
220
+ children: [
221
+ {
222
+ key: :profile,
223
+ label: "collavre.users.profile",
224
+ type: :button,
225
+ path: -> { Collavre::Engine.routes.url_helpers.user_path(Current.user) },
226
+ html_class: "popup-menu-item",
227
+ priority: 100
228
+ },
229
+ {
230
+ key: :sign_out,
231
+ label: "app.sign_out",
232
+ type: :button,
233
+ path: -> { Collavre::Engine.routes.url_helpers.session_path },
234
+ method: :delete,
235
+ priority: 900
236
+ }
237
+ ]
238
+ )
239
+ end
240
+ end
76
241
  end
77
242
  end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Collavre
4
+ # Registry for third-party integrations (Slack, GitHub, Notion, etc.)
5
+ # Allows extensions to register themselves and provide UI components
6
+ # without modifying the core Collavre engine.
7
+ #
8
+ # @example Registering an integration
9
+ # Collavre::IntegrationRegistry.register(:slack, {
10
+ # label: "Slack",
11
+ # icon: "slack",
12
+ # description: "Sync chat messages with Slack channels",
13
+ # routes: CollavreSlack::Engine.routes.url_helpers,
14
+ # creative_menu_partial: "collavre_slack/integrations/creative_menu",
15
+ # settings_partial: "collavre_slack/integrations/settings"
16
+ # })
17
+ #
18
+ class IntegrationRegistry
19
+ include Singleton
20
+
21
+ def initialize
22
+ @integrations = {}
23
+ @mutex = Mutex.new
24
+ end
25
+
26
+ # Register a new integration
27
+ # @param name [Symbol] Unique identifier for the integration
28
+ # @param config [Hash] Configuration options
29
+ # @option config [String] :label Display name
30
+ # @option config [String] :icon Icon identifier (optional)
31
+ # @option config [String] :description Brief description (optional)
32
+ # @option config [Object] :routes Engine routes url_helpers
33
+ # @option config [String] :creative_menu_partial Partial for creative action menu
34
+ # @option config [String] :settings_partial Partial for settings page (optional)
35
+ # @option config [Proc] :enabled_for Lambda to check if enabled for a creative (optional)
36
+ def register(name, config)
37
+ integration = Integration.new(name, config)
38
+ @mutex.synchronize do
39
+ @integrations[name.to_sym] = integration
40
+ end
41
+ Rails.logger.info("[Collavre] Integration registered: #{name}")
42
+ integration
43
+ end
44
+
45
+ # Unregister an integration
46
+ def unregister(name)
47
+ @mutex.synchronize do
48
+ @integrations.delete(name.to_sym)
49
+ end
50
+ end
51
+
52
+ # Get a specific integration by name
53
+ def find(name)
54
+ @mutex.synchronize do
55
+ @integrations[name.to_sym]
56
+ end
57
+ end
58
+
59
+ # Get all registered integrations
60
+ def all
61
+ @mutex.synchronize do
62
+ @integrations.values
63
+ end
64
+ end
65
+
66
+ # Iterate over all integrations
67
+ def each(&block)
68
+ all.each(&block)
69
+ end
70
+
71
+ # Check if any integrations are registered
72
+ def any?
73
+ @mutex.synchronize do
74
+ @integrations.any?
75
+ end
76
+ end
77
+
78
+ # Clear all integrations (useful for testing)
79
+ def reset!
80
+ @mutex.synchronize do
81
+ @integrations = {}
82
+ end
83
+ end
84
+
85
+ # Class methods for convenient access
86
+ class << self
87
+ delegate :register, :unregister, :find, :all, :each, :any?, :reset!, to: :instance
88
+ end
89
+ end
90
+
91
+ # Represents a registered integration
92
+ class Integration
93
+ attr_reader :name, :label, :icon, :description, :routes,
94
+ :creative_menu_partial, :settings_partial, :enabled_for
95
+
96
+ def initialize(name, config)
97
+ @name = name.to_sym
98
+ @label = config[:label] || name.to_s.titleize
99
+ @icon = config[:icon]
100
+ @description = config[:description]
101
+ @routes = config[:routes]
102
+ @creative_menu_partial = config[:creative_menu_partial]
103
+ @settings_partial = config[:settings_partial]
104
+ @enabled_for = config[:enabled_for] || ->(_creative) { true }
105
+
106
+ validate!
107
+ end
108
+
109
+ # Check if this integration is enabled for a specific creative
110
+ def enabled_for?(creative)
111
+ return true unless @enabled_for.respond_to?(:call)
112
+ @enabled_for.call(creative)
113
+ end
114
+
115
+ # Generate a path using the integration's routes
116
+ def path_for(method_name, **args)
117
+ return nil unless @routes
118
+ return nil unless @routes.respond_to?(method_name)
119
+ @routes.public_send(method_name, **args)
120
+ end
121
+
122
+ private
123
+
124
+ def validate!
125
+ raise ArgumentError, "Integration must have a :label" unless @label.present?
126
+ raise ArgumentError, "Integration must have a :creative_menu_partial" unless @creative_menu_partial.present?
127
+ end
128
+ end
129
+ end
@@ -1,3 +1,3 @@
1
1
  module Collavre
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/collavre.rb CHANGED
@@ -2,6 +2,8 @@ require "collavre/version"
2
2
  require "collavre/configuration"
3
3
  require "collavre/engine"
4
4
  require "collavre/user_extensions"
5
+ require "collavre/integration_registry"
6
+ require "navigation/registry"
5
7
 
6
8
  module Collavre
7
9
  class << self
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navigation
4
+ class Registry
5
+ include Singleton
6
+
7
+ DEFAULT_PRIORITY = 500
8
+ DEFAULT_SECTION = :main
9
+
10
+ def initialize
11
+ @items = []
12
+ @mutex = Mutex.new
13
+ end
14
+
15
+ # Register a new navigation item or replace an existing one with the same key
16
+ def register(item)
17
+ item = normalize_item(item)
18
+ validate_item!(item)
19
+
20
+ @mutex.synchronize do
21
+ # Remove existing item with same key if present
22
+ @items.reject! { |i| i[:key] == item[:key] }
23
+ @items << item
24
+ end
25
+ item
26
+ end
27
+
28
+ # Remove an item by key
29
+ def unregister(key)
30
+ @mutex.synchronize do
31
+ @items.reject! { |i| i[:key] == key.to_sym }
32
+ end
33
+ end
34
+
35
+ # Modify an existing item
36
+ def modify(key, **changes)
37
+ @mutex.synchronize do
38
+ item = @items.find { |i| i[:key] == key.to_sym }
39
+ raise ArgumentError, "Navigation item not found: #{key}" unless item
40
+
41
+ item.merge!(changes)
42
+ end
43
+ end
44
+
45
+ # Add a child item to a parent
46
+ def add_child(parent_key, child)
47
+ child = normalize_item(child)
48
+ validate_item!(child)
49
+
50
+ @mutex.synchronize do
51
+ parent = @items.find { |i| i[:key] == parent_key.to_sym }
52
+ raise ArgumentError, "Parent navigation item not found: #{parent_key}" unless parent
53
+
54
+ parent[:children] ||= []
55
+ # Remove existing child with same key if present
56
+ parent[:children].reject! { |c| c[:key] == child[:key] }
57
+ parent[:children] << child
58
+ parent[:children].sort_by! { |c| c[:priority] }
59
+ end
60
+ child
61
+ end
62
+
63
+ # Get all items for a specific section, sorted by priority
64
+ def items_for_section(section)
65
+ @mutex.synchronize do
66
+ @items
67
+ .select { |i| i[:section] == section.to_sym }
68
+ .sort_by { |i| i[:priority] }
69
+ end
70
+ end
71
+
72
+ # Get all items, sorted by priority
73
+ def all
74
+ @mutex.synchronize do
75
+ @items.sort_by { |i| i[:priority] }
76
+ end
77
+ end
78
+
79
+ # Get a specific item by key
80
+ def find(key)
81
+ @mutex.synchronize do
82
+ @items.find { |i| i[:key] == key.to_sym }
83
+ end
84
+ end
85
+
86
+ # Clear all items (useful for testing or reloading)
87
+ def reset!
88
+ @mutex.synchronize do
89
+ @items = []
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def normalize_item(item)
96
+ item = item.dup
97
+ item[:key] = item[:key]&.to_sym
98
+ item[:section] ||= DEFAULT_SECTION
99
+ item[:section] = item[:section].to_sym
100
+ item[:priority] ||= DEFAULT_PRIORITY
101
+ item[:type] ||= :button
102
+ item[:type] = item[:type].to_sym
103
+ item[:desktop] = true unless item.key?(:desktop)
104
+ item[:mobile] = true unless item.key?(:mobile)
105
+ item[:requires_auth] ||= false
106
+ item[:requires_user] ||= false
107
+ if item[:children]
108
+ item[:children].map! { |c| normalize_item(c) }
109
+ item[:children].sort_by! { |c| c[:priority] }
110
+ end
111
+ item
112
+ end
113
+
114
+ def validate_item!(item, parent_key: nil)
115
+ context = parent_key ? " (child of #{parent_key})" : ""
116
+ raise ArgumentError, "Navigation item must have a :key#{context}" unless item[:key]
117
+ raise ArgumentError, "Navigation item must have a :label#{context}" unless item[:label]
118
+ raise ArgumentError, "Navigation item must have a :key" unless item[:key]
119
+ raise ArgumentError, "Navigation item must have a :label" unless item[:label]
120
+
121
+ valid_types = %i[button link component partial divider raw popup]
122
+ unless valid_types.include?(item[:type])
123
+ raise ArgumentError, "Invalid navigation item type: #{item[:type]}#{context}. Valid types: #{valid_types.join(', ')}"
124
+ end
125
+
126
+ # Validate children recursively
127
+ item[:children]&.each { |child| validate_item!(child, parent_key: item[:key]) }
128
+ end
129
+ end
130
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: collavre
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Collavre
@@ -172,8 +172,11 @@ files:
172
172
  - app/channels/collavre/comments_presence_channel.rb
173
173
  - app/channels/collavre/slide_view_channel.rb
174
174
  - app/channels/collavre/topics_channel.rb
175
+ - app/components/collavre/autocomplete_popup_component.html.erb
176
+ - app/components/collavre/autocomplete_popup_component.rb
175
177
  - app/components/collavre/avatar_component.html.erb
176
178
  - app/components/collavre/avatar_component.rb
179
+ - app/components/collavre/command_menu_component.rb
177
180
  - app/components/collavre/inbox/badge_component.html.erb
178
181
  - app/components/collavre/inbox/badge_component.rb
179
182
  - app/components/collavre/plans_timeline_component.html.erb
@@ -182,7 +185,6 @@ files:
182
185
  - app/components/collavre/popup_menu_component.rb
183
186
  - app/components/collavre/progress_filter_component.html.erb
184
187
  - app/components/collavre/progress_filter_component.rb
185
- - app/components/collavre/user_mention_menu_component.html.erb
186
188
  - app/components/collavre/user_mention_menu_component.rb
187
189
  - app/controllers/collavre/application_controller.rb
188
190
  - app/controllers/collavre/attachments_controller.rb
@@ -204,13 +206,14 @@ files:
204
206
  - app/controllers/collavre/google_auth_controller.rb
205
207
  - app/controllers/collavre/inbox_items_controller.rb
206
208
  - app/controllers/collavre/invites_controller.rb
207
- - app/controllers/collavre/notion_auth_controller.rb
208
209
  - app/controllers/collavre/passwords_controller.rb
209
210
  - app/controllers/collavre/plans_controller.rb
210
211
  - app/controllers/collavre/sessions_controller.rb
211
212
  - app/controllers/collavre/topics_controller.rb
212
213
  - app/controllers/collavre/user_themes_controller.rb
213
214
  - app/controllers/collavre/users_controller.rb
215
+ - app/errors/collavre/approval_pending_error.rb
216
+ - app/errors/collavre/cancelled_error.rb
214
217
  - app/helpers/collavre/application_helper.rb
215
218
  - app/helpers/collavre/comments_helper.rb
216
219
  - app/helpers/collavre/creatives_helper.rb
@@ -271,7 +274,10 @@ files:
271
274
  - app/javascript/lib/responsive_images.js
272
275
  - app/javascript/lib/turbo_stream_actions.js
273
276
  - app/javascript/lib/utils/markdown.js
277
+ - app/javascript/modules/__tests__/creative_progress.test.js
278
+ - app/javascript/modules/command_menu.js
274
279
  - app/javascript/modules/creative_guide.js
280
+ - app/javascript/modules/creative_progress.js
275
281
  - app/javascript/modules/creative_row_editor.js
276
282
  - app/javascript/modules/creative_row_swipe.js
277
283
  - app/javascript/modules/creatives.js
@@ -290,8 +296,6 @@ files:
290
296
  - app/javascript/utils/clipboard.js
291
297
  - app/jobs/collavre/ai_agent_job.rb
292
298
  - app/jobs/collavre/inbox_summary_job.rb
293
- - app/jobs/collavre/notion_export_job.rb
294
- - app/jobs/collavre/notion_sync_job.rb
295
299
  - app/jobs/collavre/permission_cache_cleanup_job.rb
296
300
  - app/jobs/collavre/permission_cache_job.rb
297
301
  - app/jobs/collavre/push_notification_job.rb
@@ -322,9 +326,6 @@ files:
322
326
  - app/models/collavre/invitation.rb
323
327
  - app/models/collavre/label.rb
324
328
  - app/models/collavre/mcp_tool.rb
325
- - app/models/collavre/notion_account.rb
326
- - app/models/collavre/notion_block_link.rb
327
- - app/models/collavre/notion_page_link.rb
328
329
  - app/models/collavre/plan.rb
329
330
  - app/models/collavre/session.rb
330
331
  - app/models/collavre/system_setting.rb
@@ -374,15 +375,14 @@ files:
374
375
  - app/services/collavre/link_preview_fetcher.rb
375
376
  - app/services/collavre/markdown_importer.rb
376
377
  - app/services/collavre/mcp_service.rb
377
- - app/services/collavre/notion_client.rb
378
- - app/services/collavre/notion_creative_exporter.rb
379
- - app/services/collavre/notion_service.rb
380
378
  - app/services/collavre/ppt_importer.rb
381
379
  - app/services/collavre/ruby_llm_interaction_logger.rb
382
380
  - app/services/collavre/system_events/context_builder.rb
383
381
  - app/services/collavre/system_events/dispatcher.rb
384
382
  - app/services/collavre/system_events/router.rb
383
+ - app/services/collavre/tools/creative_create_service.rb
385
384
  - app/services/collavre/tools/creative_retrieval_service.rb
385
+ - app/services/collavre/tools/creative_update_service.rb
386
386
  - app/views/admin/shared/_tabs.html.erb
387
387
  - app/views/collavre/comments/_activity_log_details.html.erb
388
388
  - app/views/collavre/comments/_comment.html.erb
@@ -391,13 +391,16 @@ files:
391
391
  - app/views/collavre/comments/_presence_avatars.html.erb
392
392
  - app/views/collavre/comments/_reaction_picker.html.erb
393
393
  - app/views/collavre/comments/_read_receipts.html.erb
394
+ - app/views/collavre/comments/fullscreen.html.erb
394
395
  - app/views/collavre/creatives/_add_button.html.erb
395
396
  - app/views/collavre/creatives/_delete_button.html.erb
396
397
  - app/views/collavre/creatives/_github_integration_modal.html.erb
397
398
  - app/views/collavre/creatives/_import_upload_zone.html.erb
398
399
  - app/views/collavre/creatives/_inline_edit_form.html.erb
400
+ - app/views/collavre/creatives/_integration_modals.html.erb
401
+ - app/views/collavre/creatives/_integration_triggers.html.erb
402
+ - app/views/collavre/creatives/_integrations_menu.html.erb
399
403
  - app/views/collavre/creatives/_mobile_actions_menu.html.erb
400
- - app/views/collavre/creatives/_notion_integration_modal.html.erb
401
404
  - app/views/collavre/creatives/_set_plan_modal.html.erb
402
405
  - app/views/collavre/creatives/_share_button.html.erb
403
406
  - app/views/collavre/creatives/edit.html.erb
@@ -446,7 +449,10 @@ files:
446
449
  - app/views/collavre/users/passkeys.html.erb
447
450
  - app/views/collavre/users/show.html.erb
448
451
  - app/views/inbox/badge_component/_count.html.erb
452
+ - app/views/layouts/collavre/chat.html.erb
449
453
  - app/views/layouts/collavre/slide.html.erb
454
+ - config/locales/ai_agent.en.yml
455
+ - config/locales/ai_agent.ko.yml
450
456
  - config/locales/comments.en.yml
451
457
  - config/locales/comments.ko.yml
452
458
  - config/locales/contacts.en.yml
@@ -464,13 +470,10 @@ files:
464
470
  - config/locales/users.en.yml
465
471
  - config/locales/users.ko.yml
466
472
  - config/routes.rb
467
- - db/migrate/20241201000000_create_notion_integrations.rb
468
473
  - db/migrate/20250128110017_create_creatives.rb
469
474
  - db/migrate/20250128120122_create_users.rb
470
475
  - db/migrate/20250128120123_create_sessions.rb
471
476
  - db/migrate/20250128123633_create_subscribers.rb
472
- - db/migrate/20250312000000_create_notion_block_links.rb
473
- - db/migrate/20250312010000_allow_multiple_notion_blocks_per_creative.rb
474
477
  - db/migrate/20250522115048_remove_name_from_creatives.rb
475
478
  - db/migrate/20250522190651_add_parent_id_to_creatives.rb
476
479
  - db/migrate/20250523133100_rename_inventory_count_to_progress.rb
@@ -557,13 +560,17 @@ files:
557
560
  - db/migrate/20260120045354_encrypt_oauth_tokens.rb
558
561
  - db/migrate/20260120162259_remove_fk_from_creative_shares_caches.rb
559
562
  - db/migrate/20260120163856_remove_timestamps_from_creative_shares_caches.rb
563
+ - db/migrate/20260131100000_migrate_active_storage_attachment_record_types.rb
564
+ - db/migrate/20260201100000_make_google_event_id_nullable.rb
560
565
  - lib/collavre.rb
561
566
  - lib/collavre/configuration.rb
562
567
  - lib/collavre/engine.rb
568
+ - lib/collavre/integration_registry.rb
563
569
  - lib/collavre/user_extensions.rb
564
570
  - lib/collavre/version.rb
565
571
  - lib/generators/collavre/install/install_generator.rb
566
572
  - lib/generators/collavre/install/templates/build.cjs.tt
573
+ - lib/navigation/registry.rb
567
574
  - lib/tasks/collavre_assets.rake
568
575
  homepage: https://collavre.com
569
576
  licenses:
@@ -1,3 +0,0 @@
1
- <div id="<%= menu_id %>" class="mention-popup common-popup" style="display:none;">
2
- <ul class="mention-results common-popup-list" data-popup-list></ul>
3
- </div>
@@ -1,25 +0,0 @@
1
- module Collavre
2
- class NotionAuthController < ApplicationController
3
- allow_unauthenticated_access only: :callback
4
- before_action -> { enforce_auth_provider!(:notion) }, only: :callback
5
-
6
- def callback
7
- auth = request.env["omniauth.auth"]
8
- notion = Collavre::NotionAccount.find_or_initialize_by(notion_uid: auth.uid)
9
-
10
- if notion.new_record?
11
- unless Current.user
12
- redirect_to collavre.new_session_path, alert: I18n.t("collavre.notion_auth.login_first")
13
- return
14
- end
15
- notion.user = Current.user
16
- end
17
-
18
- notion.token = auth.credentials.token
19
- notion.workspace_name = auth.info.name
20
- notion.save!
21
-
22
- redirect_to creatives_path, notice: I18n.t("collavre.notion_auth.connected")
23
- end
24
- end
25
- end
@@ -1,30 +0,0 @@
1
- module Collavre
2
- class NotionExportJob < ApplicationJob
3
- queue_as :default
4
-
5
- def perform(creative, notion_account, parent_page_id = nil)
6
- service = NotionService.new(user: notion_account.user)
7
-
8
- begin
9
- # Export the creative tree to Notion
10
- link = service.sync_creative(creative, parent_page_id: parent_page_id)
11
-
12
- Rails.logger.info("Successfully exported creative #{creative.id} to Notion page #{link.page_id}")
13
-
14
- # You could add broadcast/notification logic here if needed
15
- # ActionCable.server.broadcast("user_#{notion_account.user.id}", {
16
- # type: 'notion_export_complete',
17
- # creative_id: creative.id,
18
- # page_url: link.page_url
19
- # })
20
-
21
- rescue NotionError => e
22
- Rails.logger.error("Notion export failed for creative #{creative.id}: #{e.message}")
23
- raise e
24
- rescue StandardError => e
25
- Rails.logger.error("Unexpected error during Notion export for creative #{creative.id}: #{e.message}")
26
- raise e
27
- end
28
- end
29
- end
30
- end