aven 0.0.3
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +35 -0
- data/Rakefile +19 -0
- data/app/assets/stylesheets/aven/application.css +14 -0
- data/app/assets/stylesheets/aven/application.tailwind.css +7 -0
- data/app/assets/stylesheets/aven/tailwind.css +224 -0
- data/app/channels/aven/chat/thread_channel.rb +39 -0
- data/app/components/aven/application_view_component.rb +15 -0
- data/app/components/aven/views/admin/dashboard/index/component.html.erb +1 -0
- data/app/components/aven/views/admin/dashboard/index/component.rb +5 -0
- data/app/components/aven/views/articles/edit/component.html.erb +14 -0
- data/app/components/aven/views/articles/edit/component.rb +14 -0
- data/app/components/aven/views/articles/form/component.html.erb +45 -0
- data/app/components/aven/views/articles/form/component.rb +27 -0
- data/app/components/aven/views/articles/index/component.html.erb +93 -0
- data/app/components/aven/views/articles/index/component.rb +29 -0
- data/app/components/aven/views/articles/new/component.html.erb +13 -0
- data/app/components/aven/views/articles/new/component.rb +14 -0
- data/app/components/aven/views/articles/show/component.html.erb +110 -0
- data/app/components/aven/views/articles/show/component.rb +34 -0
- data/app/components/aven/views/oauth/error/component.html.erb +44 -0
- data/app/components/aven/views/oauth/error/component.rb +30 -0
- data/app/components/aven/views/static/index/component.html.erb +17 -0
- data/app/components/aven/views/static/index/component.rb +16 -0
- data/app/components/aven/views/static/index/controller.js +7 -0
- data/app/controllers/aven/admin/base.rb +16 -0
- data/app/controllers/aven/admin/dashboard_controller.rb +9 -0
- data/app/controllers/aven/agentic/agents_controller.rb +56 -0
- data/app/controllers/aven/agentic/documents_controller.rb +51 -0
- data/app/controllers/aven/agentic/mcp_controller.rb +124 -0
- data/app/controllers/aven/agentic/tools_controller.rb +37 -0
- data/app/controllers/aven/ai/text_controller.rb +41 -0
- data/app/controllers/aven/application_controller.rb +27 -0
- data/app/controllers/aven/articles_controller.rb +114 -0
- data/app/controllers/aven/auth_controller.rb +12 -0
- data/app/controllers/aven/chat/threads_controller.rb +67 -0
- data/app/controllers/aven/oauth/auth0_controller.rb +84 -0
- data/app/controllers/aven/oauth/base_controller.rb +183 -0
- data/app/controllers/aven/oauth/documentation/auth0.md +387 -0
- data/app/controllers/aven/oauth/documentation/entra_id.md +608 -0
- data/app/controllers/aven/oauth/documentation/github.md +329 -0
- data/app/controllers/aven/oauth/documentation/google.md +253 -0
- data/app/controllers/aven/oauth/entra_id_controller.rb +92 -0
- data/app/controllers/aven/oauth/github_controller.rb +91 -0
- data/app/controllers/aven/oauth/google_controller.rb +64 -0
- data/app/controllers/aven/static_controller.rb +7 -0
- data/app/controllers/aven/tags_controller.rb +44 -0
- data/app/controllers/aven/workspaces_controller.rb +20 -0
- data/app/controllers/concerns/aven/authentication.rb +49 -0
- data/app/controllers/concerns/aven/controller_helpers.rb +38 -0
- data/app/helpers/aven/application_helper.rb +16 -0
- data/app/javascript/aven/application.js +3 -0
- data/app/javascript/aven/controllers/application.js +5 -0
- data/app/javascript/aven/controllers/index.js +11 -0
- data/app/jobs/aven/agentic/document_embedding_job.rb +28 -0
- data/app/jobs/aven/agentic/document_ocr_job.rb +28 -0
- data/app/jobs/aven/application_job.rb +4 -0
- data/app/jobs/aven/chat/calculate_cost_job.rb +26 -0
- data/app/jobs/aven/chat/run_job.rb +27 -0
- data/app/mailers/aven/application_mailer.rb +6 -0
- data/app/models/aven/agentic/agent.rb +76 -0
- data/app/models/aven/agentic/agent_document.rb +37 -0
- data/app/models/aven/agentic/agent_tool.rb +37 -0
- data/app/models/aven/agentic/document.rb +162 -0
- data/app/models/aven/agentic/document_embedding.rb +39 -0
- data/app/models/aven/agentic/tool.rb +106 -0
- data/app/models/aven/agentic/tool_parameter.rb +56 -0
- data/app/models/aven/application_record.rb +5 -0
- data/app/models/aven/article.rb +86 -0
- data/app/models/aven/article_attachment.rb +18 -0
- data/app/models/aven/article_relationship.rb +26 -0
- data/app/models/aven/chat/message.rb +135 -0
- data/app/models/aven/chat/thread.rb +159 -0
- data/app/models/aven/import/entry.rb +45 -0
- data/app/models/aven/import/item_link.rb +36 -0
- data/app/models/aven/import/processor.rb +123 -0
- data/app/models/aven/import.rb +102 -0
- data/app/models/aven/item/embed.rb +54 -0
- data/app/models/aven/item/embeddable.rb +141 -0
- data/app/models/aven/item/linkable.rb +212 -0
- data/app/models/aven/item/schema/builder.rb +139 -0
- data/app/models/aven/item/schemaed.rb +252 -0
- data/app/models/aven/item/schemas/base.rb +108 -0
- data/app/models/aven/item.rb +128 -0
- data/app/models/aven/item_link.rb +43 -0
- data/app/models/aven/item_schema.rb +87 -0
- data/app/models/aven/log.rb +66 -0
- data/app/models/aven/loggable.rb +20 -0
- data/app/models/aven/user.rb +40 -0
- data/app/models/aven/workspace.rb +93 -0
- data/app/models/aven/workspace_role.rb +46 -0
- data/app/models/aven/workspace_user.rb +54 -0
- data/app/models/aven/workspace_user_role.rb +38 -0
- data/app/models/concerns/aven/agentic/document_embeddable.rb +58 -0
- data/app/models/concerns/aven/searchable.rb +61 -0
- data/app/services/aven/agentic/dynamic_tool_builder.rb +81 -0
- data/app/services/aven/agentic/mcp/adapter.rb +77 -0
- data/app/services/aven/agentic/mcp/result_formatter.rb +57 -0
- data/app/services/aven/agentic/mcp/server_factory.rb +43 -0
- data/app/services/aven/agentic/ocr/base_extractor.rb +39 -0
- data/app/services/aven/agentic/ocr/excel_extractor.rb +43 -0
- data/app/services/aven/agentic/ocr/image_extractor.rb +22 -0
- data/app/services/aven/agentic/ocr/pdf_extractor.rb +48 -0
- data/app/services/aven/agentic/ocr/processor.rb +36 -0
- data/app/services/aven/agentic/ocr/textract_client.rb +131 -0
- data/app/services/aven/agentic/ocr/word_extractor.rb +34 -0
- data/app/services/aven/agentic/tool_result_formatter.rb +76 -0
- data/app/services/aven/agentic/tools/base.rb +55 -0
- data/app/services/aven/agentic/tools/concerns/boolean_filtering.rb +40 -0
- data/app/services/aven/agentic/tools/concerns/enum_filtering.rb +47 -0
- data/app/services/aven/agentic/tools/concerns/geo_filtering.rb +56 -0
- data/app/services/aven/agentic/tools/concerns/range_filtering.rb +51 -0
- data/app/services/aven/chat/broadcaster.rb +59 -0
- data/app/services/aven/chat/config.rb +93 -0
- data/app/services/aven/chat/message_builder.rb +42 -0
- data/app/services/aven/chat/orchestrator.rb +69 -0
- data/app/services/aven/chat/runner.rb +105 -0
- data/app/services/aven/chat/title_generator.rb +61 -0
- data/app/services/aven/external/gmail_client.rb +173 -0
- data/app/services/aven/external/google_contacts_client.rb +95 -0
- data/app/views/layouts/aven/admin.html.erb +16 -0
- data/app/views/layouts/aven/application.html.erb +18 -0
- data/config/importmap.rb +16 -0
- data/config/routes.rb +63 -0
- data/db/migrate/20200101000001_create_aven_users.rb +19 -0
- data/db/migrate/20200101000002_create_aven_workspaces.rb +14 -0
- data/db/migrate/20200101000003_create_aven_workspace_users.rb +12 -0
- data/db/migrate/20200101000004_create_aven_workspace_roles.rb +13 -0
- data/db/migrate/20200101000005_create_aven_workspace_user_roles.rb +12 -0
- data/db/migrate/20200101000006_create_aven_logs.rb +21 -0
- data/db/migrate/20200101000009_create_aven_items.rb +17 -0
- data/db/migrate/20200101000010_create_aven_item_links.rb +17 -0
- data/db/migrate/20200101000011_create_aven_agentic_tools.rb +19 -0
- data/db/migrate/20200101000012_create_aven_agentic_tool_parameters.rb +20 -0
- data/db/migrate/20200101000013_create_aven_agentic_documents.rb +22 -0
- data/db/migrate/20200101000014_create_aven_agentic_document_embeddings.rb +18 -0
- data/db/migrate/20200101000015_create_aven_agentic_agents.rb +18 -0
- data/db/migrate/20200101000016_create_aven_agentic_agent_tools.rb +13 -0
- data/db/migrate/20200101000017_create_aven_agentic_agent_documents.rb +13 -0
- data/db/migrate/20200101000018_create_aven_chat_threads.rb +19 -0
- data/db/migrate/20200101000019_create_aven_chat_messages.rb +26 -0
- data/db/migrate/20200101000020_add_pg_search_support.rb +21 -0
- data/db/migrate/20200101000021_create_aven_item_schemas.rb +18 -0
- data/db/migrate/20200101000022_create_aven_imports.rb +23 -0
- data/db/migrate/20200101000023_create_aven_import_entries.rb +13 -0
- data/db/migrate/20200101000024_create_aven_import_item_links.rb +13 -0
- data/db/migrate/20200101000025_create_aven_articles.rb +19 -0
- data/db/migrate/20200101000026_create_aven_article_attachments.rb +13 -0
- data/db/migrate/20200101000027_create_aven_article_relationships.rb +15 -0
- data/lib/aven/configuration.rb +87 -0
- data/lib/aven/engine.rb +43 -0
- data/lib/aven/model/tenant_model.rb +91 -0
- data/lib/aven/model.rb +6 -0
- data/lib/aven/version.rb +3 -0
- data/lib/aven.rb +8 -0
- data/lib/tasks/annotate_rb.rake +10 -0
- data/lib/tasks/aven_tasks.rake +21 -0
- metadata +426 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1e46cb60a74a930eaadac2b01e7cc7192fbc24126e578cf19706b0e5aecf4167
|
|
4
|
+
data.tar.gz: 79ba33013d1b4c96d96e21d92042e83111b9a9dcf28859b9e7825ab56e19f1e1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5bcd618b6d3ed1d035576e14cb845ea20b72517e0b597975a66d937d8eb3483c85a44d06b4926701620342ce7547156d11e569cff00f8e1b4d8d660a3f81a9b0
|
|
7
|
+
data.tar.gz: a7a714d2af2e325a8eca535a8a11c39fb7d31d5f82ca53e8f142a50066131098e0e5bec5abe37742ce1ed3f1b64ef5a5e28862642742c30eba21481fa5b253d4
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright Ben
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Aven
|
|
2
|
+
|
|
3
|
+
Short description and motivation.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
How to use my plugin.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
Add this line to your application's Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem "aven"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
And then execute:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
$ bundle
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or install it yourself as:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
$ gem install aven
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Contributing
|
|
30
|
+
|
|
31
|
+
Contribution directions go here.
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require "bundler/setup"
|
|
2
|
+
|
|
3
|
+
APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
|
|
4
|
+
load "rails/tasks/engine.rake"
|
|
5
|
+
|
|
6
|
+
load "rails/tasks/statistics.rake"
|
|
7
|
+
|
|
8
|
+
require "bundler/gem_tasks"
|
|
9
|
+
|
|
10
|
+
require "rake/testtask"
|
|
11
|
+
|
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
|
13
|
+
t.libs << "test"
|
|
14
|
+
t.pattern = "test/**/*_test.rb"
|
|
15
|
+
t.verbose = false
|
|
16
|
+
t.warning = false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
task default: :test
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
|
11
|
+
* It is generally better to create a new file per style scope.
|
|
12
|
+
*
|
|
13
|
+
*= require_self
|
|
14
|
+
*/
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/*! tailwindcss v4.1.13 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer theme, base, components, utilities;
|
|
3
|
+
@layer theme {
|
|
4
|
+
:root, :host {
|
|
5
|
+
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
|
6
|
+
'Noto Color Emoji';
|
|
7
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
|
|
8
|
+
monospace;
|
|
9
|
+
--color-slate-50: oklch(98.4% 0.003 247.858);
|
|
10
|
+
--color-slate-100: oklch(96.8% 0.007 247.896);
|
|
11
|
+
--color-stone-700: oklch(37.4% 0.01 67.558);
|
|
12
|
+
--default-font-family: var(--font-sans);
|
|
13
|
+
--default-mono-font-family: var(--font-mono);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
@layer base {
|
|
17
|
+
*, ::after, ::before, ::backdrop, ::file-selector-button {
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
margin: 0;
|
|
20
|
+
padding: 0;
|
|
21
|
+
border: 0 solid;
|
|
22
|
+
}
|
|
23
|
+
html, :host {
|
|
24
|
+
line-height: 1.5;
|
|
25
|
+
-webkit-text-size-adjust: 100%;
|
|
26
|
+
tab-size: 4;
|
|
27
|
+
font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji');
|
|
28
|
+
font-feature-settings: var(--default-font-feature-settings, normal);
|
|
29
|
+
font-variation-settings: var(--default-font-variation-settings, normal);
|
|
30
|
+
-webkit-tap-highlight-color: transparent;
|
|
31
|
+
}
|
|
32
|
+
hr {
|
|
33
|
+
height: 0;
|
|
34
|
+
color: inherit;
|
|
35
|
+
border-top-width: 1px;
|
|
36
|
+
}
|
|
37
|
+
abbr:where([title]) {
|
|
38
|
+
-webkit-text-decoration: underline dotted;
|
|
39
|
+
text-decoration: underline dotted;
|
|
40
|
+
}
|
|
41
|
+
h1, h2, h3, h4, h5, h6 {
|
|
42
|
+
font-size: inherit;
|
|
43
|
+
font-weight: inherit;
|
|
44
|
+
}
|
|
45
|
+
a {
|
|
46
|
+
color: inherit;
|
|
47
|
+
-webkit-text-decoration: inherit;
|
|
48
|
+
text-decoration: inherit;
|
|
49
|
+
}
|
|
50
|
+
b, strong {
|
|
51
|
+
font-weight: bolder;
|
|
52
|
+
}
|
|
53
|
+
code, kbd, samp, pre {
|
|
54
|
+
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace);
|
|
55
|
+
font-feature-settings: var(--default-mono-font-feature-settings, normal);
|
|
56
|
+
font-variation-settings: var(--default-mono-font-variation-settings, normal);
|
|
57
|
+
font-size: 1em;
|
|
58
|
+
}
|
|
59
|
+
small {
|
|
60
|
+
font-size: 80%;
|
|
61
|
+
}
|
|
62
|
+
sub, sup {
|
|
63
|
+
font-size: 75%;
|
|
64
|
+
line-height: 0;
|
|
65
|
+
position: relative;
|
|
66
|
+
vertical-align: baseline;
|
|
67
|
+
}
|
|
68
|
+
sub {
|
|
69
|
+
bottom: -0.25em;
|
|
70
|
+
}
|
|
71
|
+
sup {
|
|
72
|
+
top: -0.5em;
|
|
73
|
+
}
|
|
74
|
+
table {
|
|
75
|
+
text-indent: 0;
|
|
76
|
+
border-color: inherit;
|
|
77
|
+
border-collapse: collapse;
|
|
78
|
+
}
|
|
79
|
+
:-moz-focusring {
|
|
80
|
+
outline: auto;
|
|
81
|
+
}
|
|
82
|
+
progress {
|
|
83
|
+
vertical-align: baseline;
|
|
84
|
+
}
|
|
85
|
+
summary {
|
|
86
|
+
display: list-item;
|
|
87
|
+
}
|
|
88
|
+
ol, ul, menu {
|
|
89
|
+
list-style: none;
|
|
90
|
+
}
|
|
91
|
+
img, svg, video, canvas, audio, iframe, embed, object {
|
|
92
|
+
display: block;
|
|
93
|
+
vertical-align: middle;
|
|
94
|
+
}
|
|
95
|
+
img, video {
|
|
96
|
+
max-width: 100%;
|
|
97
|
+
height: auto;
|
|
98
|
+
}
|
|
99
|
+
button, input, select, optgroup, textarea, ::file-selector-button {
|
|
100
|
+
font: inherit;
|
|
101
|
+
font-feature-settings: inherit;
|
|
102
|
+
font-variation-settings: inherit;
|
|
103
|
+
letter-spacing: inherit;
|
|
104
|
+
color: inherit;
|
|
105
|
+
border-radius: 0;
|
|
106
|
+
background-color: transparent;
|
|
107
|
+
opacity: 1;
|
|
108
|
+
}
|
|
109
|
+
:where(select:is([multiple], [size])) optgroup {
|
|
110
|
+
font-weight: bolder;
|
|
111
|
+
}
|
|
112
|
+
:where(select:is([multiple], [size])) optgroup option {
|
|
113
|
+
padding-inline-start: 20px;
|
|
114
|
+
}
|
|
115
|
+
::file-selector-button {
|
|
116
|
+
margin-inline-end: 4px;
|
|
117
|
+
}
|
|
118
|
+
::placeholder {
|
|
119
|
+
opacity: 1;
|
|
120
|
+
}
|
|
121
|
+
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
|
|
122
|
+
::placeholder {
|
|
123
|
+
color: currentcolor;
|
|
124
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
125
|
+
color: color-mix(in oklab, currentcolor 50%, transparent);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
textarea {
|
|
130
|
+
resize: vertical;
|
|
131
|
+
}
|
|
132
|
+
::-webkit-search-decoration {
|
|
133
|
+
-webkit-appearance: none;
|
|
134
|
+
}
|
|
135
|
+
::-webkit-date-and-time-value {
|
|
136
|
+
min-height: 1lh;
|
|
137
|
+
text-align: inherit;
|
|
138
|
+
}
|
|
139
|
+
::-webkit-datetime-edit {
|
|
140
|
+
display: inline-flex;
|
|
141
|
+
}
|
|
142
|
+
::-webkit-datetime-edit-fields-wrapper {
|
|
143
|
+
padding: 0;
|
|
144
|
+
}
|
|
145
|
+
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
|
|
146
|
+
padding-block: 0;
|
|
147
|
+
}
|
|
148
|
+
::-webkit-calendar-picker-indicator {
|
|
149
|
+
line-height: 1;
|
|
150
|
+
}
|
|
151
|
+
:-moz-ui-invalid {
|
|
152
|
+
box-shadow: none;
|
|
153
|
+
}
|
|
154
|
+
button, input:where([type='button'], [type='reset'], [type='submit']), ::file-selector-button {
|
|
155
|
+
appearance: button;
|
|
156
|
+
}
|
|
157
|
+
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
|
|
158
|
+
height: auto;
|
|
159
|
+
}
|
|
160
|
+
[hidden]:where(:not([hidden='until-found'])) {
|
|
161
|
+
display: none !important;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
@layer utilities {
|
|
165
|
+
.visible {
|
|
166
|
+
visibility: visible;
|
|
167
|
+
}
|
|
168
|
+
.absolute {
|
|
169
|
+
position: absolute;
|
|
170
|
+
}
|
|
171
|
+
.fixed {
|
|
172
|
+
position: fixed;
|
|
173
|
+
}
|
|
174
|
+
.relative {
|
|
175
|
+
position: relative;
|
|
176
|
+
}
|
|
177
|
+
.isolate {
|
|
178
|
+
isolation: isolate;
|
|
179
|
+
}
|
|
180
|
+
.container {
|
|
181
|
+
width: 100%;
|
|
182
|
+
@media (width >= 40rem) {
|
|
183
|
+
max-width: 40rem;
|
|
184
|
+
}
|
|
185
|
+
@media (width >= 48rem) {
|
|
186
|
+
max-width: 48rem;
|
|
187
|
+
}
|
|
188
|
+
@media (width >= 64rem) {
|
|
189
|
+
max-width: 64rem;
|
|
190
|
+
}
|
|
191
|
+
@media (width >= 80rem) {
|
|
192
|
+
max-width: 80rem;
|
|
193
|
+
}
|
|
194
|
+
@media (width >= 96rem) {
|
|
195
|
+
max-width: 96rem;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
.block {
|
|
199
|
+
display: block;
|
|
200
|
+
}
|
|
201
|
+
.contents {
|
|
202
|
+
display: contents;
|
|
203
|
+
}
|
|
204
|
+
.hidden {
|
|
205
|
+
display: none;
|
|
206
|
+
}
|
|
207
|
+
.inline {
|
|
208
|
+
display: inline;
|
|
209
|
+
}
|
|
210
|
+
.table {
|
|
211
|
+
display: table;
|
|
212
|
+
}
|
|
213
|
+
.bg-slate-50 {
|
|
214
|
+
background-color: var(--color-slate-50);
|
|
215
|
+
}
|
|
216
|
+
.bg-slate-100 {
|
|
217
|
+
background-color: var(--color-slate-100);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
@layer base {
|
|
221
|
+
html {
|
|
222
|
+
color: var(--color-stone-700);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven
|
|
4
|
+
module Chat
|
|
5
|
+
class ThreadChannel < ActionCable::Channel::Base
|
|
6
|
+
def subscribed
|
|
7
|
+
thread = find_thread
|
|
8
|
+
return reject unless thread
|
|
9
|
+
|
|
10
|
+
stream_for thread
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def unsubscribed
|
|
14
|
+
stop_all_streams
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def find_thread
|
|
20
|
+
thread_id = params[:thread_id]
|
|
21
|
+
return nil unless thread_id
|
|
22
|
+
|
|
23
|
+
# Verify user has access to this thread
|
|
24
|
+
if current_user
|
|
25
|
+
Aven::Chat::Thread
|
|
26
|
+
.joins(:workspace)
|
|
27
|
+
.joins("INNER JOIN aven_workspace_users ON aven_workspace_users.workspace_id = aven_chat_threads.workspace_id")
|
|
28
|
+
.where(aven_workspace_users: { user_id: current_user.id })
|
|
29
|
+
.find_by(id: thread_id)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def current_user
|
|
34
|
+
# Access current_user from connection
|
|
35
|
+
connection.current_user if connection.respond_to?(:current_user)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Aven
|
|
2
|
+
class ApplicationViewComponent < Aeros::ApplicationViewComponent
|
|
3
|
+
def controller_name
|
|
4
|
+
# Match JS autoload naming for components/controllers:
|
|
5
|
+
# - aven/controllers/hello_controller -> aven--hello
|
|
6
|
+
# - aven/components/views/static/index/controller -> aven--views--static--index
|
|
7
|
+
name = self.class.name
|
|
8
|
+
.sub(/^Aven::/, "")
|
|
9
|
+
.sub(/::Component$/, "")
|
|
10
|
+
.underscore
|
|
11
|
+
|
|
12
|
+
"aven--#{name.gsub('/', '--').gsub('_', '-')}"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ok admin
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<%= ui("page", title: "Edit Article", subtitle: article.title) do |page| %>
|
|
2
|
+
<% page.with_actions_area do %>
|
|
3
|
+
<%= ui("button", label: "View", href: routes.article_path(article), variant: :outline) %>
|
|
4
|
+
<%= ui("button", label: "Back to Articles", href: routes.articles_path, variant: :outline) %>
|
|
5
|
+
<% end %>
|
|
6
|
+
|
|
7
|
+
<div class="max-w-4xl">
|
|
8
|
+
<%= render Aven::Views::Articles::Form::Component.new(
|
|
9
|
+
article: article,
|
|
10
|
+
url: routes.article_path(article),
|
|
11
|
+
current_user: current_user
|
|
12
|
+
) %>
|
|
13
|
+
</div>
|
|
14
|
+
<% end %>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven::Views::Articles::Edit
|
|
4
|
+
class Component < Aven::ApplicationViewComponent
|
|
5
|
+
option :article
|
|
6
|
+
option :current_user, optional: true
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def routes
|
|
11
|
+
Aven::Engine.routes.url_helpers
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<%= form_with model: article, url: url, builder: Aeros::FormBuilder, class: "space-y-6" do |f| %>
|
|
2
|
+
<%= f.text_field :title, label: "Title", required: true %>
|
|
3
|
+
|
|
4
|
+
<%= f.text_area_ai_field :intro,
|
|
5
|
+
label: "Introduction",
|
|
6
|
+
ai_url: routes.ai_text_generate_path,
|
|
7
|
+
system_prompts: ["Write a compelling 2-3 sentence introduction for this article."],
|
|
8
|
+
rows: 3 %>
|
|
9
|
+
|
|
10
|
+
<%= f.text_area_ai_field :description,
|
|
11
|
+
label: "Content",
|
|
12
|
+
ai_url: routes.ai_text_generate_path,
|
|
13
|
+
system_prompts: ["Write clear, engaging article content. Use markdown formatting."],
|
|
14
|
+
rows: 12 %>
|
|
15
|
+
|
|
16
|
+
<%= f.tagging_field :tag_list,
|
|
17
|
+
label: "Tags",
|
|
18
|
+
tags_url: routes.tags_path(format: :json),
|
|
19
|
+
create_url: routes.tags_path,
|
|
20
|
+
selected_tags: article.tag_list.to_a %>
|
|
21
|
+
|
|
22
|
+
<%= f.file_field :main_visual, label: "Main Visual", accept: "image/*" %>
|
|
23
|
+
|
|
24
|
+
<% if article.main_visual.attached? %>
|
|
25
|
+
<div class="mt-2">
|
|
26
|
+
<%= image_tag article.main_visual, class: "max-w-xs rounded-lg" %>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
29
|
+
|
|
30
|
+
<%= f.attachments_field :article_attachments,
|
|
31
|
+
label: "Attachments",
|
|
32
|
+
accept: "image/*,application/pdf",
|
|
33
|
+
max_files: 20,
|
|
34
|
+
existing: existing_attachments,
|
|
35
|
+
direct_upload_url: helpers.main_app.rails_direct_uploads_url %>
|
|
36
|
+
|
|
37
|
+
<%= f.datetime_field :published_at,
|
|
38
|
+
label: "Publish Date",
|
|
39
|
+
helper_text: "Leave blank to save as draft" %>
|
|
40
|
+
|
|
41
|
+
<div class="flex items-center gap-4 pt-4">
|
|
42
|
+
<%= ui("button", label: article.persisted? ? "Update Article" : "Create Article", type: "submit") %>
|
|
43
|
+
<%= ui("button", label: "Cancel", href: routes.articles_path, variant: :outline) %>
|
|
44
|
+
</div>
|
|
45
|
+
<% end %>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven::Views::Articles::Form
|
|
4
|
+
class Component < Aven::ApplicationViewComponent
|
|
5
|
+
option :article
|
|
6
|
+
option :url
|
|
7
|
+
option :current_user, optional: true
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def routes
|
|
12
|
+
Aven::Engine.routes.url_helpers
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def existing_attachments
|
|
16
|
+
article.sorted_attachments.select { |a| a.file.attached? }.map do |attachment|
|
|
17
|
+
{
|
|
18
|
+
id: attachment.id,
|
|
19
|
+
position: attachment.position,
|
|
20
|
+
signed_id: attachment.file.signed_id,
|
|
21
|
+
url: helpers.url_for(attachment.file),
|
|
22
|
+
filename: attachment.file.filename.to_s
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<%= ui("page", title: "Articles", description: "Manage your articles and blog posts") do |page| %>
|
|
2
|
+
<% page.with_actions_area do %>
|
|
3
|
+
<%= ui("button", label: "New Article", href: routes.new_article_path) %>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<% if articles.any? %>
|
|
7
|
+
<div class="bg-white rounded-lg border border-gray-200 overflow-hidden">
|
|
8
|
+
<table class="min-w-full divide-y divide-gray-200">
|
|
9
|
+
<thead class="bg-gray-50">
|
|
10
|
+
<tr>
|
|
11
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
12
|
+
Title
|
|
13
|
+
</th>
|
|
14
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
15
|
+
Status
|
|
16
|
+
</th>
|
|
17
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
18
|
+
Author
|
|
19
|
+
</th>
|
|
20
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
21
|
+
Date
|
|
22
|
+
</th>
|
|
23
|
+
<th scope="col" class="relative px-6 py-3">
|
|
24
|
+
<span class="sr-only">Actions</span>
|
|
25
|
+
</th>
|
|
26
|
+
</tr>
|
|
27
|
+
</thead>
|
|
28
|
+
<tbody class="bg-white divide-y divide-gray-200">
|
|
29
|
+
<% articles.each do |article| %>
|
|
30
|
+
<tr class="hover:bg-gray-50">
|
|
31
|
+
<td class="px-6 py-4">
|
|
32
|
+
<div class="flex items-center">
|
|
33
|
+
<% if article.main_visual.attached? %>
|
|
34
|
+
<%= image_tag article.main_visual.variant(resize_to_limit: [40, 40]),
|
|
35
|
+
class: "h-10 w-10 rounded object-cover mr-3" %>
|
|
36
|
+
<% end %>
|
|
37
|
+
<div>
|
|
38
|
+
<%= link_to article.title,
|
|
39
|
+
routes.article_path(article),
|
|
40
|
+
class: "text-sm font-medium text-gray-900 hover:text-blue-600" %>
|
|
41
|
+
<% if article.tag_list.any? %>
|
|
42
|
+
<div class="flex gap-1 mt-1">
|
|
43
|
+
<% article.tag_list.first(3).each do |tag| %>
|
|
44
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-600">
|
|
45
|
+
<%= tag %>
|
|
46
|
+
</span>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% if article.tag_list.size > 3 %>
|
|
49
|
+
<span class="text-xs text-gray-400">+<%= article.tag_list.size - 3 %></span>
|
|
50
|
+
<% end %>
|
|
51
|
+
</div>
|
|
52
|
+
<% end %>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</td>
|
|
56
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
57
|
+
<% badge = status_badge(article) %>
|
|
58
|
+
<%= ui("badge", label: badge[:label], variant: badge[:variant]) %>
|
|
59
|
+
</td>
|
|
60
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
61
|
+
<%= article.author&.name || "—" %>
|
|
62
|
+
</td>
|
|
63
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
64
|
+
<%= format_date(article.published_at || article.created_at) %>
|
|
65
|
+
</td>
|
|
66
|
+
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
67
|
+
<%= link_to "Edit",
|
|
68
|
+
routes.edit_article_path(article),
|
|
69
|
+
class: "text-blue-600 hover:text-blue-900 mr-4" %>
|
|
70
|
+
<%= button_to "Delete",
|
|
71
|
+
routes.article_path(article),
|
|
72
|
+
method: :delete,
|
|
73
|
+
form: { data: { turbo_confirm: "Are you sure you want to delete this article?" } },
|
|
74
|
+
class: "text-red-600 hover:text-red-900" %>
|
|
75
|
+
</td>
|
|
76
|
+
</tr>
|
|
77
|
+
<% end %>
|
|
78
|
+
</tbody>
|
|
79
|
+
</table>
|
|
80
|
+
</div>
|
|
81
|
+
<% else %>
|
|
82
|
+
<div class="text-center py-12 bg-white rounded-lg border border-gray-200">
|
|
83
|
+
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
84
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z" />
|
|
85
|
+
</svg>
|
|
86
|
+
<h3 class="mt-2 text-sm font-medium text-gray-900">No articles</h3>
|
|
87
|
+
<p class="mt-1 text-sm text-gray-500">Get started by creating a new article.</p>
|
|
88
|
+
<div class="mt-6">
|
|
89
|
+
<%= ui("button", label: "New Article", href: routes.new_article_path) %>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
<% end %>
|
|
93
|
+
<% end %>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven::Views::Articles::Index
|
|
4
|
+
class Component < Aven::ApplicationViewComponent
|
|
5
|
+
option :articles
|
|
6
|
+
option :current_user, optional: true
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def routes
|
|
11
|
+
Aven::Engine.routes.url_helpers
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def status_badge(article)
|
|
15
|
+
if article.published?
|
|
16
|
+
{ label: "Published", variant: :success }
|
|
17
|
+
elsif article.scheduled?
|
|
18
|
+
{ label: "Scheduled", variant: :warning }
|
|
19
|
+
else
|
|
20
|
+
{ label: "Draft", variant: :secondary }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def format_date(date)
|
|
25
|
+
return "—" unless date
|
|
26
|
+
date.strftime("%b %d, %Y")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<%= ui("page", title: "New Article") do |page| %>
|
|
2
|
+
<% page.with_actions_area do %>
|
|
3
|
+
<%= ui("button", label: "Back to Articles", href: routes.articles_path, variant: :outline) %>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<div class="max-w-4xl">
|
|
7
|
+
<%= render Aven::Views::Articles::Form::Component.new(
|
|
8
|
+
article: article,
|
|
9
|
+
url: routes.articles_path,
|
|
10
|
+
current_user: current_user
|
|
11
|
+
) %>
|
|
12
|
+
</div>
|
|
13
|
+
<% end %>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aven::Views::Articles::New
|
|
4
|
+
class Component < Aven::ApplicationViewComponent
|
|
5
|
+
option :article
|
|
6
|
+
option :current_user, optional: true
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def routes
|
|
11
|
+
Aven::Engine.routes.url_helpers
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|