collavre 0.6.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/collavre/comments_popup.css +157 -1
  3. data/app/assets/stylesheets/collavre/creatives.css +73 -1
  4. data/app/assets/stylesheets/collavre/org_chart.css +319 -0
  5. data/app/assets/stylesheets/collavre/popup.css +65 -0
  6. data/app/controllers/collavre/application_controller.rb +13 -0
  7. data/app/controllers/collavre/comments_controller.rb +10 -183
  8. data/app/controllers/collavre/concerns/exportable.rb +30 -0
  9. data/app/controllers/collavre/concerns/shareable.rb +28 -0
  10. data/app/controllers/collavre/concerns/slide_viewable.rb +37 -0
  11. data/app/controllers/collavre/concerns/tree_manageable.rb +141 -0
  12. data/app/controllers/collavre/creative_imports_controller.rb +6 -0
  13. data/app/controllers/collavre/creative_invitations_controller.rb +46 -0
  14. data/app/controllers/collavre/creative_plans_controller.rb +1 -1
  15. data/app/controllers/collavre/creative_shares_controller.rb +84 -14
  16. data/app/controllers/collavre/creatives_controller.rb +70 -194
  17. data/app/controllers/collavre/google_auth_controller.rb +3 -0
  18. data/app/controllers/collavre/invites_controller.rb +2 -1
  19. data/app/controllers/collavre/sessions_controller.rb +3 -0
  20. data/app/controllers/collavre/topics_controller.rb +39 -2
  21. data/app/controllers/collavre/users_controller.rb +5 -404
  22. data/app/controllers/concerns/collavre/comments/approval_actions.rb +108 -0
  23. data/app/controllers/concerns/collavre/comments/batch_operations.rb +55 -0
  24. data/app/controllers/concerns/collavre/comments/conversion.rb +46 -0
  25. data/app/controllers/concerns/collavre/users_controller/admin_operations.rb +74 -0
  26. data/app/controllers/concerns/collavre/users_controller/ai_user_management.rb +119 -0
  27. data/app/controllers/concerns/collavre/users_controller/contact_management.rb +166 -0
  28. data/app/controllers/concerns/collavre/users_controller/profile_and_settings.rb +102 -0
  29. data/app/controllers/concerns/collavre/users_controller/registration.rb +63 -0
  30. data/app/helpers/collavre/application_helper.rb +1 -0
  31. data/app/helpers/collavre/creatives_helper.rb +12 -9
  32. data/app/helpers/collavre/navigation_helper.rb +1 -1
  33. data/app/javascript/collavre.js +0 -1
  34. data/app/javascript/controllers/comments/contexts_controller.js +363 -0
  35. data/app/javascript/controllers/comments/form_controller.js +29 -2
  36. data/app/javascript/controllers/comments/list_controller.js +5 -0
  37. data/app/javascript/controllers/comments/popup_controller.js +66 -38
  38. data/app/javascript/controllers/comments/presence_controller.js +2 -10
  39. data/app/javascript/controllers/comments/topics_controller.js +34 -10
  40. data/app/javascript/controllers/index.js +9 -1
  41. data/app/javascript/controllers/org_chart_controller.js +46 -0
  42. data/app/javascript/controllers/share_modal_controller.js +369 -0
  43. data/app/javascript/creatives/drag_drop/event_handlers.js +42 -1
  44. data/app/javascript/lib/api/creatives.js +12 -0
  45. data/app/javascript/lib/api/csrf_fetch.js +35 -0
  46. data/app/javascript/lib/api/drag_drop.js +17 -0
  47. data/app/javascript/modules/command_menu.js +40 -0
  48. data/app/javascript/modules/creative_row_editor.js +88 -0
  49. data/app/javascript/modules/slide_view.js +2 -1
  50. data/app/jobs/collavre/ai_agent_job.rb +23 -53
  51. data/app/jobs/collavre/compress_job.rb +1 -1
  52. data/app/models/collavre/comment.rb +2 -1
  53. data/app/models/collavre/creative/describable.rb +1 -1
  54. data/app/models/collavre/creative.rb +51 -0
  55. data/app/models/collavre/user.rb +12 -3
  56. data/app/services/collavre/ai_agent/a2a_dispatcher.rb +68 -0
  57. data/app/services/collavre/ai_agent/agent_lifecycle_manager.rb +89 -0
  58. data/app/services/collavre/ai_agent/message_builder.rb +85 -6
  59. data/app/services/collavre/ai_agent/response_finalizer.rb +97 -0
  60. data/app/services/collavre/ai_agent/response_streamer.rb +56 -0
  61. data/app/services/collavre/ai_agent_service.rb +130 -183
  62. data/app/services/collavre/auto_theme_generator.rb +1 -1
  63. data/app/services/collavre/command_menu_service.rb +7 -0
  64. data/app/services/collavre/comments/concerns/workflow_support.rb +115 -0
  65. data/app/services/collavre/comments/work_command.rb +3 -17
  66. data/app/services/collavre/comments/workflow_executor.rb +7 -75
  67. data/app/services/collavre/creatives/plan_tagger.rb +14 -3
  68. data/app/services/collavre/gemini_parent_recommender.rb +1 -1
  69. data/app/services/collavre/orchestration/agent_context_builder.rb +1 -3
  70. data/app/services/collavre/orchestration/policy_resolver.rb +0 -19
  71. data/app/services/collavre/tools/creative_retrieval_service.rb +3 -2
  72. data/app/services/collavre/tools/cron_list_service.rb +1 -1
  73. data/app/views/collavre/comments/_comments_popup.html.erb +12 -1
  74. data/app/views/collavre/creatives/_inline_edit_form.html.erb +13 -0
  75. data/app/views/collavre/creatives/_share_button.html.erb +4 -1
  76. data/app/views/collavre/creatives/_share_modal.html.erb +31 -1
  77. data/app/views/collavre/creatives/index.html.erb +5 -5
  78. data/app/views/collavre/creatives/slide_view.html.erb +1 -1
  79. data/app/views/collavre/users/{_contact_management.html.erb → _contact_list.html.erb} +4 -8
  80. data/app/views/collavre/users/_org_chart.html.erb +68 -0
  81. data/app/views/collavre/users/_org_chart_node.html.erb +169 -0
  82. data/app/views/collavre/users/new_ai.html.erb +9 -0
  83. data/app/views/collavre/users/show.html.erb +32 -8
  84. data/config/locales/comments.en.yml +4 -0
  85. data/config/locales/comments.ko.yml +4 -0
  86. data/config/locales/contacts.en.yml +31 -0
  87. data/config/locales/contacts.ko.yml +31 -0
  88. data/config/locales/contexts.en.yml +8 -0
  89. data/config/locales/contexts.ko.yml +8 -0
  90. data/config/locales/creatives.en.yml +6 -0
  91. data/config/locales/creatives.ko.yml +6 -0
  92. data/config/locales/users.en.yml +1 -0
  93. data/config/locales/users.ko.yml +1 -0
  94. data/config/routes.rb +8 -1
  95. data/lib/collavre/version.rb +1 -1
  96. metadata +28 -10
  97. data/app/javascript/lib/lexical/__tests__/action_text_attachment_node.test.jsx +0 -91
  98. data/app/javascript/lib/lexical/action_text_attachment_node.js +0 -459
  99. data/app/javascript/lib/lexical/dom_attachment_utils.js +0 -66
  100. data/app/javascript/modules/share_modal.js +0 -76
  101. data/app/javascript/modules/share_user_popup.js +0 -77
  102. data/app/services/collavre/orchestration/self_reflection_evaluator.rb +0 -231
  103. data/app/views/collavre/comments/_presence_avatars.html.erb +0 -8
  104. data/app/views/collavre/creatives/_delete_button.html.erb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88ee0fe394fdf6b52cb501be92fbac6b05e549adf30aa46937d7e9a14a690e7c
4
- data.tar.gz: e3573f4001310e3227e6084f5544af98412ba341d217cec06731974d57fc154d
3
+ metadata.gz: 6414531da275a2a96ac42eec4a925fe11edb59df7c816149519fcd65dae15776
4
+ data.tar.gz: 2e520883472dd008086893bbd05cb41fd9f9920b64c5daa4850cb9e820a8136a
5
5
  SHA512:
6
- metadata.gz: a139147e03c807d07ab876d053172acfb736956fb5d6a8e1d519a070b83913caba150389153329461963129394b52af20cbd53b7e0506a68f5c4210dc6625cc2
7
- data.tar.gz: f9f2ea3a2921c3baee34452e8908cd48e93b59692124b54b672312255eb8a25eb77f8b3dad61f3ce17e6533f9d79e7b11ce7bd928dfcc74ea336dc30329204b0
6
+ metadata.gz: 6fe49fbc8ed7aa39949890d6417e4eb9bcf8d00d7499c7876a4b06e71dd7b0273b12e085587ed8ea18b0e43c441f27127d771f08114349f3de0e143f46c5addc
7
+ data.tar.gz: 79b811c324024e3ab61b9af8aa297f5a7a940cb8983614d2c428b8bbc1e0bf363a1f45c89e9093d9931aa5ccb7490644ee623cc7f4e5d322eace86e8419df7c0
@@ -1,6 +1,6 @@
1
1
  #comments-popup {
2
2
  display: none;
3
- position: absolute;
3
+ position: fixed;
4
4
  right: 2em;
5
5
  /* top: 10em; */
6
6
  z-index: var(--layer-modal);
@@ -13,6 +13,8 @@
13
13
  right 0.25s ease, bottom 0.25s ease, border-radius 0.25s ease,
14
14
  box-shadow 0.25s ease, padding 0.25s ease;
15
15
  max-width: calc(100vw - 0.5em) !important;
16
+ overscroll-behavior: contain;
17
+ overflow: hidden;
16
18
  }
17
19
 
18
20
  body.chat-fullscreen {
@@ -45,6 +47,11 @@ body.chat-fullscreen {
45
47
  gap: 0.75em;
46
48
  }
47
49
 
50
+ .comments-popup-header h3 {
51
+ margin: 0;
52
+ line-height: 1.3;
53
+ }
54
+
48
55
  .comments-popup-actions {
49
56
  display: inline-flex;
50
57
  align-items: center;
@@ -91,6 +98,7 @@ body.chat-fullscreen {
91
98
  #comments-list {
92
99
  padding-top: 0.5em;
93
100
  overflow-y: auto;
101
+ overscroll-behavior: contain;
94
102
  /* height: 380px; */
95
103
  flex-grow: 1;
96
104
  /* align to vertical bottom */
@@ -895,6 +903,154 @@ body.chat-fullscreen {
895
903
  filter: grayscale(1);
896
904
  }
897
905
 
906
+ /* --- Context Chips --- */
907
+ .comment-contexts-list {
908
+ display: flex;
909
+ flex-wrap: nowrap;
910
+ align-items: center;
911
+ gap: 0.4em;
912
+ padding: 0.25em 0;
913
+ overflow-x: auto;
914
+ overflow-y: visible;
915
+ scrollbar-width: none;
916
+ -ms-overflow-style: none;
917
+ min-height: 26px; /* Ensure chips (22px + padding) are never clipped */
918
+ }
919
+
920
+ .comment-contexts-list:empty {
921
+ display: none;
922
+ }
923
+
924
+ .comment-contexts-list::-webkit-scrollbar {
925
+ display: none;
926
+ }
927
+
928
+ .context-chip {
929
+ display: inline-flex;
930
+ align-items: center;
931
+ flex-shrink: 0;
932
+ gap: var(--space-1);
933
+ padding: 0.15em 0.5em;
934
+ border-radius: 10px;
935
+ background: var(--color-secondary-background);
936
+ border: 1px solid var(--color-border);
937
+ color: var(--color-text);
938
+ font-size: 0.75em;
939
+ cursor: pointer;
940
+ transition: all 0.2s;
941
+ white-space: nowrap;
942
+ height: 22px;
943
+ box-sizing: border-box;
944
+ }
945
+
946
+ .context-chip:hover {
947
+ background: var(--color-border);
948
+ }
949
+
950
+ .context-chip.context-disabled {
951
+ opacity: 0.4;
952
+ text-decoration: line-through;
953
+ }
954
+
955
+ .context-chip.context-inherited {
956
+ border-style: dashed;
957
+ }
958
+
959
+ .context-chip.context-dragging {
960
+ opacity: 0.5;
961
+ }
962
+
963
+ .context-chip.context-drag-over-left {
964
+ border-left: 3px solid var(--color-active);
965
+ margin-left: -1px;
966
+ }
967
+
968
+ .context-chip.context-drag-over-right {
969
+ border-right: 3px solid var(--color-active);
970
+ margin-right: -1px;
971
+ }
972
+
973
+ .context-chip[draggable="true"] {
974
+ cursor: grab;
975
+ }
976
+
977
+ .context-chip[draggable="true"]:active {
978
+ cursor: grabbing;
979
+ }
980
+
981
+ .navigate-context-btn {
982
+ background: none;
983
+ border: none;
984
+ color: var(--color-text-muted);
985
+ cursor: pointer;
986
+ font-size: 0.9em;
987
+ padding: 0 0.15em;
988
+ line-height: 1;
989
+ margin-left: 0.1em;
990
+ }
991
+
992
+ .navigate-context-btn:hover {
993
+ color: var(--color-active);
994
+ }
995
+
996
+ .delete-context-btn {
997
+ background: none;
998
+ border: none;
999
+ color: var(--color-text-muted);
1000
+ cursor: pointer;
1001
+ font-size: 0.9em;
1002
+ padding: 0 0.15em;
1003
+ line-height: 1;
1004
+ margin-left: 0.1em;
1005
+ }
1006
+
1007
+ .delete-context-btn:hover {
1008
+ color: var(--color-danger);
1009
+ }
1010
+
1011
+ .add-context-btn {
1012
+ display: inline-flex;
1013
+ align-items: center;
1014
+ justify-content: center;
1015
+ flex-shrink: 0;
1016
+ width: 22px;
1017
+ height: 22px;
1018
+ border-radius: 50%;
1019
+ background: var(--color-secondary-background);
1020
+ border: 1px dashed var(--color-border);
1021
+ color: var(--color-text-muted);
1022
+ font-size: 0.85em;
1023
+ cursor: pointer;
1024
+ transition: all 0.2s;
1025
+ }
1026
+
1027
+ .add-context-btn:hover {
1028
+ background: var(--color-border);
1029
+ color: var(--color-text);
1030
+ }
1031
+
1032
+ /* Context toggle button in header */
1033
+ .context-toggle-btn {
1034
+ font-size: 0.75em;
1035
+ padding: 0.15em 0.4em;
1036
+ border-radius: 8px;
1037
+ background: none;
1038
+ border: 1px solid transparent;
1039
+ cursor: pointer;
1040
+ transition: all 0.2s;
1041
+ white-space: nowrap;
1042
+ }
1043
+
1044
+ .context-toggle-btn:hover {
1045
+ background: var(--color-secondary-background);
1046
+ }
1047
+
1048
+ .context-toggle-btn.context-toggle-active {
1049
+ background: var(--color-secondary-active);
1050
+ color: white;
1051
+ border-color: var(--color-secondary-active);
1052
+ }
1053
+
898
1054
  .comment-topics-list {
899
1055
  display: flex;
900
1056
  flex-wrap: nowrap;
@@ -435,7 +435,10 @@ creative-tree-row:not([expanded]) .creative-toggle-btn {
435
435
  background-color: var(--border-drag-over);
436
436
  }
437
437
 
438
- .creative-row:hover {
438
+ .creative-row:hover,
439
+ .creative-row.level-1:hover,
440
+ .creative-row.level-2:hover,
441
+ .creative-row.level-3:hover {
439
442
  background-color: var(--border-color);
440
443
  }
441
444
 
@@ -606,4 +609,73 @@ creative-tree-row:not([expanded]) .creative-toggle-btn {
606
609
 
607
610
  .comments-btn .badge[data-count="0"] {
608
611
  background: var(--color-brand);
612
+ }
613
+
614
+ /* Metadata popup styles — mirrors #comments-popup positioning */
615
+ .metadata-popup {
616
+ position: absolute;
617
+ right: 2em;
618
+ z-index: var(--layer-modal);
619
+ width: 400px;
620
+ max-width: calc(100vw - 1em);
621
+ max-height: 60vh;
622
+ background: var(--surface-bg);
623
+ border: 1px solid var(--border-color);
624
+ border-radius: var(--radius-3);
625
+ padding: var(--space-3);
626
+ box-shadow: var(--shadow-3);
627
+ display: flex;
628
+ flex-direction: column;
629
+ }
630
+
631
+ .metadata-popup-header {
632
+ display: flex;
633
+ justify-content: space-between;
634
+ align-items: center;
635
+ margin-bottom: var(--space-2);
636
+ font-weight: var(--weight-6);
637
+ color: var(--text-primary);
638
+ }
639
+
640
+ .metadata-popup-header button {
641
+ background: transparent;
642
+ border: none;
643
+ cursor: pointer;
644
+ font-size: var(--text-3);
645
+ color: var(--text-muted);
646
+ padding: 0;
647
+ line-height: 1;
648
+ }
649
+
650
+ .metadata-popup-header button:hover {
651
+ color: var(--text-primary);
652
+ }
653
+
654
+ #metadata-yaml-editor {
655
+ flex: 1;
656
+ width: 100%;
657
+ min-height: 200px;
658
+ box-sizing: border-box;
659
+ font-family: var(--font-mono);
660
+ font-size: var(--text-0);
661
+ line-height: var(--leading-2);
662
+ padding: var(--space-2);
663
+ border: 1px solid var(--border-color);
664
+ border-radius: var(--radius-2);
665
+ background: var(--surface-input);
666
+ color: var(--text-primary);
667
+ resize: vertical;
668
+ }
669
+
670
+ #metadata-save-btn {
671
+ margin-top: var(--space-2);
672
+ align-self: flex-end;
673
+ }
674
+
675
+ @media (max-width: 768px) {
676
+ .metadata-popup {
677
+ right: 0.5em;
678
+ left: 0.5em;
679
+ width: auto;
680
+ }
609
681
  }
@@ -0,0 +1,319 @@
1
+ .org-chart-tree {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--space-3);
5
+ }
6
+
7
+ .org-chart-group {
8
+ border: 1px solid var(--border-color);
9
+ border-radius: var(--radius-2);
10
+ overflow: hidden;
11
+ }
12
+
13
+ .org-chart-group .org-chart-group {
14
+ border: none;
15
+ border-top: 1px solid var(--border-color);
16
+ border-radius: 0;
17
+ }
18
+
19
+ .org-chart-creative-row {
20
+ display: flex;
21
+ align-items: center;
22
+ gap: var(--space-2);
23
+ padding: var(--space-2) var(--space-3);
24
+ background-color: var(--surface-section);
25
+ cursor: pointer;
26
+ list-style: none;
27
+ user-select: none;
28
+ }
29
+
30
+ .org-chart-creative-row::-webkit-details-marker {
31
+ display: none;
32
+ }
33
+
34
+ .org-chart-creative-row::before {
35
+ content: '▶';
36
+ font-size: 0.7em;
37
+ color: var(--text-muted);
38
+ transition: transform 0.15s ease;
39
+ flex-shrink: 0;
40
+ }
41
+
42
+ details[open] > .org-chart-creative-row::before {
43
+ transform: rotate(90deg);
44
+ }
45
+
46
+ .org-chart-creative-row {
47
+ --depth: 0;
48
+ padding-left: calc(var(--space-5) * var(--depth));
49
+ }
50
+
51
+ .org-chart-depth-0 {
52
+ background-color: var(--surface-section);
53
+ font-weight: var(--weight-6);
54
+ }
55
+
56
+ .org-chart-creative-row:not(.org-chart-depth-0) {
57
+ background-color: transparent;
58
+ font-weight: var(--weight-4);
59
+ font-size: max(0.85em, 1em - var(--depth) * 0.05em);
60
+ }
61
+
62
+ .org-chart-creative-link {
63
+ color: var(--text-primary);
64
+ text-decoration: none;
65
+ flex: 1;
66
+ min-width: 0;
67
+ overflow: hidden;
68
+ text-overflow: ellipsis;
69
+ white-space: nowrap;
70
+ }
71
+
72
+ .org-chart-creative-link:hover {
73
+ color: var(--color-link);
74
+ }
75
+
76
+ .org-chart-owner-badge {
77
+ font-size: var(--text-0);
78
+ color: var(--text-muted);
79
+ padding: 2px 6px;
80
+ border-radius: var(--radius-1);
81
+ background-color: var(--surface-input);
82
+ white-space: nowrap;
83
+ }
84
+
85
+ /* Manage permissions button on creative row */
86
+ .org-chart-manage-btn {
87
+ margin-left: auto;
88
+ }
89
+
90
+ .org-chart-content {
91
+ border-top: 1px solid var(--border-color);
92
+ }
93
+
94
+ .org-chart-members {
95
+ padding: var(--space-1) 0;
96
+ }
97
+
98
+ .org-chart-members,
99
+ .org-chart-children,
100
+ .org-chart-no-members {
101
+ --indent: 0;
102
+ }
103
+
104
+ .org-chart-members .org-chart-member-row,
105
+ .org-chart-no-members {
106
+ padding-left: calc(var(--space-5) * (var(--indent) + 1) + var(--space-4));
107
+ }
108
+
109
+ .org-chart-toolbar {
110
+ display: flex;
111
+ justify-content: flex-end;
112
+ margin-bottom: var(--space-2);
113
+ }
114
+
115
+ .org-chart-children {
116
+ padding: 0;
117
+ }
118
+
119
+ /* Grid layout for column alignment */
120
+ .org-chart-member-row {
121
+ display: grid;
122
+ grid-template-columns: 1fr auto auto;
123
+ align-items: center;
124
+ padding: var(--space-1) var(--space-3);
125
+ gap: var(--space-3);
126
+ }
127
+
128
+ .org-chart-member-row:hover {
129
+ background-color: var(--surface-input);
130
+ }
131
+
132
+ /* Column 1: User info (avatar + name + email) */
133
+ .org-chart-member-info {
134
+ display: flex;
135
+ align-items: center;
136
+ gap: var(--space-2);
137
+ min-width: 0;
138
+ }
139
+
140
+ .org-chart-member-name-group {
141
+ display: flex;
142
+ align-items: baseline;
143
+ gap: var(--space-2);
144
+ min-width: 0;
145
+ overflow: hidden;
146
+ }
147
+
148
+ .org-chart-member-name {
149
+ overflow: hidden;
150
+ text-overflow: ellipsis;
151
+ white-space: nowrap;
152
+ color: var(--text-primary);
153
+ text-decoration: none;
154
+ font-weight: var(--weight-5);
155
+ }
156
+
157
+ .org-chart-member-name:hover {
158
+ color: var(--color-link);
159
+ }
160
+
161
+ .org-chart-member-email {
162
+ font-size: var(--text-0);
163
+ color: var(--text-muted);
164
+ white-space: nowrap;
165
+ overflow: hidden;
166
+ text-overflow: ellipsis;
167
+ }
168
+
169
+ /* Column 2: Permission badge/select */
170
+ .org-chart-member-permission {
171
+ display: flex;
172
+ align-items: center;
173
+ justify-content: center;
174
+ min-width: 80px;
175
+ }
176
+
177
+ /* Column 3: Actions */
178
+ .org-chart-member-actions {
179
+ display: flex;
180
+ gap: var(--space-1);
181
+ justify-content: flex-end;
182
+ min-width: 120px;
183
+ }
184
+
185
+ /* Permission badges */
186
+ .org-chart-permission-badge {
187
+ font-size: var(--text-0);
188
+ padding: 2px 8px;
189
+ border-radius: var(--radius-round);
190
+ white-space: nowrap;
191
+ }
192
+
193
+ .org-chart-permission-admin {
194
+ background-color: var(--color-danger);
195
+ color: white;
196
+ }
197
+
198
+ .org-chart-permission-write {
199
+ background-color: var(--color-success);
200
+ color: white;
201
+ }
202
+
203
+ .org-chart-permission-feedback {
204
+ background-color: var(--color-warning);
205
+ color: var(--text-primary);
206
+ }
207
+
208
+ .org-chart-permission-read {
209
+ background-color: var(--text-muted);
210
+ color: white;
211
+ }
212
+
213
+ .org-chart-permission-no_access {
214
+ background-color: var(--surface-input);
215
+ color: var(--text-muted);
216
+ }
217
+
218
+ /* Share direction labels */
219
+ .org-chart-direction {
220
+ font-size: var(--text-0);
221
+ white-space: nowrap;
222
+ }
223
+
224
+ .org-chart-direction-outgoing {
225
+ color: var(--color-brand);
226
+ }
227
+
228
+ .org-chart-direction-incoming {
229
+ color: var(--color-warning);
230
+ }
231
+
232
+ /* Permission select dropdown */
233
+ .org-chart-permission-select {
234
+ font-size: var(--text-0);
235
+ padding: 2px 6px;
236
+ border-radius: var(--radius-round);
237
+ border: 1px solid transparent;
238
+ cursor: pointer;
239
+ appearance: auto;
240
+ white-space: nowrap;
241
+ }
242
+
243
+ .org-chart-permission-select.org-chart-permission-admin {
244
+ background-color: var(--color-danger);
245
+ color: white;
246
+ }
247
+
248
+ .org-chart-permission-select.org-chart-permission-write {
249
+ background-color: var(--color-success);
250
+ color: white;
251
+ }
252
+
253
+ .org-chart-permission-select.org-chart-permission-feedback {
254
+ background-color: var(--color-warning);
255
+ color: var(--text-primary);
256
+ }
257
+
258
+ .org-chart-permission-select.org-chart-permission-read {
259
+ background-color: var(--text-muted);
260
+ color: white;
261
+ }
262
+
263
+ .org-chart-permission-select.org-chart-permission-no_access {
264
+ background-color: var(--surface-input);
265
+ color: var(--text-muted);
266
+ }
267
+
268
+ .org-chart-no-members {
269
+ color: var(--text-muted);
270
+ font-size: var(--text-0);
271
+ padding: var(--space-1) var(--space-5);
272
+ margin: 0;
273
+ }
274
+
275
+ /* Horizontal scroll instead of wrapping */
276
+ .org-chart-members {
277
+ overflow-x: auto;
278
+ -webkit-overflow-scrolling: touch;
279
+ }
280
+
281
+ .org-chart-member-row {
282
+ min-width: max-content;
283
+ }
284
+
285
+ /* Pending invitation styles */
286
+ .org-chart-pending-badge {
287
+ font-size: var(--text-00);
288
+ color: var(--color-warning);
289
+ font-weight: var(--weight-5);
290
+ }
291
+
292
+ .org-chart-invitation-row {
293
+ opacity: 0.85;
294
+ }
295
+
296
+ /* Unassigned users section */
297
+ .org-chart-unassigned {
298
+ margin-top: var(--space-4);
299
+ border-top: 1px solid var(--color-border);
300
+ padding-top: var(--space-3);
301
+ }
302
+
303
+ .org-chart-unassigned-title {
304
+ font-size: var(--text-1);
305
+ font-weight: var(--weight-5);
306
+ color: var(--text-muted);
307
+ margin-bottom: var(--space-2);
308
+ }
309
+
310
+ /* View switcher */
311
+ .contacts-view-switcher {
312
+ display: flex;
313
+ gap: var(--space-2);
314
+ margin-bottom: var(--space-3);
315
+ }
316
+
317
+ .contacts-description {
318
+ margin: 0 0 var(--space-2) 0;
319
+ }
@@ -20,6 +20,34 @@
20
20
  overflow-y: auto;
21
21
  }
22
22
 
23
+ /* Ensure autocomplete popup inside share modal works without mention_menu.css */
24
+ #share-creative-modal .common-popup {
25
+ position: absolute;
26
+ z-index: var(--layer-modal, 100);
27
+ background: var(--surface-section, #fff);
28
+ border: 1px solid var(--border-color, #ddd);
29
+ box-shadow: var(--shadow-2, 0 2px 8px rgba(0,0,0,.15));
30
+ border-radius: 6px;
31
+ padding: 0.35em;
32
+ max-width: min(420px, 90vw);
33
+ }
34
+ #share-creative-modal .common-popup ul,
35
+ #share-creative-modal .common-popup-list {
36
+ list-style: none;
37
+ margin: 0;
38
+ padding: 0;
39
+ max-height: 260px;
40
+ overflow-y: auto;
41
+ }
42
+ #share-creative-modal .common-popup-list li {
43
+ list-style: none;
44
+ padding: 0.35em 0.5em;
45
+ cursor: pointer;
46
+ }
47
+ #share-creative-modal .common-popup-list li:hover {
48
+ background: var(--border-drag-over, #f0f0f0);
49
+ }
50
+
23
51
  .share-grid {
24
52
  list-style: none;
25
53
  padding: 0;
@@ -115,6 +143,43 @@
115
143
  color: var(--danger);
116
144
  }
117
145
 
146
+ .share-modal-message {
147
+ padding: var(--space-2) var(--space-3);
148
+ border-radius: var(--radius-2);
149
+ margin-bottom: var(--space-3);
150
+ font-size: var(--text-0);
151
+ animation: share-modal-message-fade 4s ease-in-out;
152
+ }
153
+ .share-modal-message-success {
154
+ background: var(--success-bg, #d4edda);
155
+ color: var(--success-text, #155724);
156
+ border: 1px solid var(--success-border, #c3e6cb);
157
+ }
158
+ .share-modal-message-error {
159
+ background: var(--danger-bg, #f8d7da);
160
+ color: var(--danger-text, #721c24);
161
+ border: 1px solid var(--danger-border, #f5c6cb);
162
+ }
163
+ @keyframes share-modal-message-fade {
164
+ 0%, 80% { opacity: 1; }
165
+ 100% { opacity: 0; }
166
+ }
167
+ .share-modal-pending {
168
+ opacity: 0.6;
169
+ }
170
+ .share-modal-spinner {
171
+ display: inline-block;
172
+ width: 12px;
173
+ height: 12px;
174
+ border: 2px solid var(--text-muted, #999);
175
+ border-top-color: transparent;
176
+ border-radius: 50%;
177
+ animation: share-spinner 0.6s linear infinite;
178
+ }
179
+ @keyframes share-spinner {
180
+ to { transform: rotate(360deg); }
181
+ }
182
+
118
183
  #github-integration-modal .github-modal-status {
119
184
  color: var(--text-muted);
120
185
  margin-bottom: 1em;
@@ -2,8 +2,21 @@ module Collavre
2
2
  class ApplicationController < ::ApplicationController
3
3
  protect_from_forgery with: :exception
4
4
 
5
+ # Include a fresh CSRF token in every response header so that
6
+ # JavaScript callers can update the stale <meta> tag after the
7
+ # browser has been in the background (OS window switch, tab
8
+ # freeze, etc.). Without this, the meta-tag token drifts out
9
+ # of sync with the session cookie and POSTs fail with 422.
10
+ after_action :set_csrf_token_header
11
+
5
12
  private
6
13
 
14
+ def set_csrf_token_header
15
+ return unless protect_against_forgery?
16
+
17
+ response.headers["X-CSRF-Token"] = form_authenticity_token
18
+ end
19
+
7
20
  # Helper to get the engine's routes
8
21
  def collavre_engine
9
22
  Collavre::Engine.routes.url_helpers