eyeloupe 0.2.0 → 0.3.1
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/CHANGELOG.md +13 -3
- data/README.md +57 -7
- data/app/assets/builds/eyeloupe.css +1 -1
- data/app/assets/javascripts/eyeloupe/controllers/eyeloupe/ai_assistant_controller.js +27 -0
- data/app/assets/javascripts/eyeloupe/controllers/eyeloupe/refresh_controller.js +3 -1
- data/app/assets/stylesheets/application.tailwind.css +8 -0
- data/app/assets/stylesheets/eyeloupe/application.css +0 -1
- data/app/controllers/eyeloupe/ai_assistant_responses_controller.rb +30 -0
- data/app/controllers/eyeloupe/data_controller.rb +2 -0
- data/app/controllers/eyeloupe/exceptions_controller.rb +29 -0
- data/app/models/eyeloupe/application_record.rb +4 -0
- data/app/models/eyeloupe/exception.rb +6 -0
- data/app/models/eyeloupe/in_request.rb +1 -0
- data/app/models/eyeloupe/out_request.rb +1 -0
- data/app/views/eyeloupe/exceptions/_frame.html.erb +39 -0
- data/app/views/eyeloupe/exceptions/index.html.erb +13 -0
- data/app/views/eyeloupe/exceptions/show.html.erb +126 -0
- data/app/views/eyeloupe/in_requests/_frame.html.erb +1 -1
- data/app/views/eyeloupe/in_requests/index.html.erb +1 -1
- data/app/views/eyeloupe/in_requests/show.html.erb +17 -1
- data/app/views/eyeloupe/out_requests/_frame.html.erb +1 -1
- data/app/views/eyeloupe/out_requests/index.html.erb +1 -1
- data/app/views/eyeloupe/out_requests/show.html.erb +17 -1
- data/app/views/layouts/eyeloupe/application.html.erb +41 -5
- data/config/importmap.rb +2 -1
- data/config/routes.rb +2 -0
- data/db/migrate/20230604190442_create_eyeloupe_exceptions.rb +21 -0
- data/lib/eyeloupe/concerns/rescuable.rb +14 -0
- data/lib/eyeloupe/configuration.rb +11 -1
- data/lib/eyeloupe/engine.rb +46 -0
- data/lib/eyeloupe/processors/exception.rb +71 -0
- data/lib/eyeloupe/processors/in_request.rb +14 -3
- data/lib/eyeloupe/processors/out_request.rb +10 -20
- data/lib/eyeloupe/request_middleware.rb +13 -1
- data/lib/eyeloupe/version.rb +1 -1
- data/lib/eyeloupe.rb +3 -1
- metadata +26 -3
- data/lib/eyeloupe/http.rb +0 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fdc0f9276e2c518c9b396f1acbc856460fb3eabdf926cbd8940bc6f33a9ec19c
|
|
4
|
+
data.tar.gz: c3fa4ae7197c7de0bcbb3790bf0b4b1eb2bd93a6bee3ecca5030b4960b5c74ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7bf1df1813f5b9791ef17c39149179b7450ba7009d61950edd1bde80edad27be1fb1ea043516dd1c51637040874e05a096c5e9a5fbe5f22379c801e9a1c8943
|
|
7
|
+
data.tar.gz: e2e24fd0d42f2e430eea07f8395e4a3a2aa6ea0ffd02a44e290339ccc1feaf92fab07af6e2e175ac7cae4a0b95ba13c2c992ecef0d9d4f55cae96085c6cca995
|
data/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
## 0.1
|
|
1
|
+
## 0.3.1
|
|
2
2
|
|
|
3
|
-
-
|
|
3
|
+
- Add optional database config (thanks to @kiskoza).
|
|
4
|
+
|
|
5
|
+
## 0.3.0
|
|
6
|
+
|
|
7
|
+
- Add exceptions: Framework + ActiveJob + Sidekiq Worker exceptions.
|
|
8
|
+
- Add OpenAI support for AI assistant in exceptions.
|
|
9
|
+
- Fix exceptions when using importmap binary by adding net/http override in railties initializer.
|
|
4
10
|
|
|
5
11
|
## 0.2.0
|
|
6
12
|
|
|
7
|
-
- Fix missing require for `pagy` gem.
|
|
13
|
+
- Fix missing require for `pagy` gem.
|
|
14
|
+
|
|
15
|
+
## 0.1.0
|
|
16
|
+
|
|
17
|
+
- Initial release including incoming and outgoing requests.
|
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[![Gem Version]
|
|
1
|
+
[](https://badge.fury.io/rb/eyeloupe)
|
|
2
2
|
|
|
3
3
|
[![Contributors][contributors-shield]][contributors-url]
|
|
4
4
|
[![Forks][forks-shield]][forks-url]
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
<img src="app/assets/images/eyeloupe/logo.png" width=120 alt="Logo" >
|
|
13
13
|
</a>
|
|
14
14
|
|
|
15
|
-
<h3 align="center">Eyeloupe</h3>
|
|
15
|
+
<h3 align="center">Eyeloupe (beta)</h3>
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
18
|
-
The elegant Rails debug assistant.
|
|
18
|
+
The elegant Rails debug assistant. AI powered.
|
|
19
19
|
<br />
|
|
20
20
|
<a href="https://github.com/alxlion/eyeloupe/issues">Report Bug</a>
|
|
21
21
|
·
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
[![Eyeloupe screenshot][eyeloupe-screen]](https://github.com/alxlion/eyeloupe)
|
|
27
27
|
|
|
28
|
-
Eyeloupe is the elegant Rails debug assistant. It helps you to debug your Rails application by providing a simple and elegant interface to view your incoming
|
|
28
|
+
Eyeloupe is the elegant Rails debug assistant. It helps you to debug your Rails application by providing a simple and elegant interface to view your incoming/outgoing requests and exceptions, powered by AI.
|
|
29
29
|
|
|
30
30
|
## Installation
|
|
31
31
|
Add this line to your application's Gemfile:
|
|
@@ -61,12 +61,45 @@ This is an example of the configuration you can add to your `initializers/eyelou
|
|
|
61
61
|
```ruby
|
|
62
62
|
Eyeloupe.configure do |config|
|
|
63
63
|
config.excluded_paths = %w[assets favicon.ico service-worker.js manifest.json]
|
|
64
|
-
config.capture =
|
|
64
|
+
config.capture = Rails.env.development?
|
|
65
|
+
config.openai_access_key = "your-openai-access-key"
|
|
66
|
+
config.openai_model = "gpt-4"
|
|
67
|
+
config.database = 'eyeloupe'
|
|
65
68
|
end
|
|
66
69
|
```
|
|
67
70
|
|
|
68
71
|
- `excluded_paths` is an array of paths you want to exclude from Eyeloupe capture. Eyeloupe adds these excluded paths to the default ones: ` %w[mini-profiler eyeloupe active_storage]`
|
|
69
72
|
- `capture` is a boolean to enable/disable Eyeloupe capture. By default, it's set to `true`.
|
|
73
|
+
- `openai_access_key` is the access key to use the OpenAI API. You can get one [here](https://platform.openai.com/).
|
|
74
|
+
- `openai_model` is the model to use for the OpenAI API. You can find the list of available models [here](https://platform.openai.com/docs/models).
|
|
75
|
+
- `database` is an optional database config Eyeloupe will use ([Database](#database)).
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
### Database
|
|
79
|
+
|
|
80
|
+
By default, Eyeloupe uses the same database as your application. If you want to use a different database to keep your production environment clean, you can add a new database config in your `config/database.yml` file:
|
|
81
|
+
|
|
82
|
+
```yml
|
|
83
|
+
development:
|
|
84
|
+
primary:
|
|
85
|
+
<<: *default
|
|
86
|
+
database: db/development.sqlite3
|
|
87
|
+
eyeloupe:
|
|
88
|
+
<<: *default
|
|
89
|
+
database: db/eyeloupe.sqlite3
|
|
90
|
+
migrations_paths: <%= Gem.loaded_specs['eyeloupe'].full_gem_path + '/db/migrate' %>
|
|
91
|
+
schema_dump: false
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Using this you can skip the `eyeloupe:install:migrations` step, but do not forget to run `rails db:migrate RAILS_ENV=eyeloupe` to setup the database.
|
|
95
|
+
|
|
96
|
+
### Exception handling
|
|
97
|
+
|
|
98
|
+
To be able to handle exceptions, be sure to disable the default Rails exception handling in your environment config file (e.g. `config/environments/development.rb`):
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
config.consider_all_requests_local = false
|
|
102
|
+
```
|
|
70
103
|
|
|
71
104
|
## Usage
|
|
72
105
|
|
|
@@ -82,6 +115,21 @@ By activating auto-fresh, every _3 seconds_ the page will be refreshed to show y
|
|
|
82
115
|
|
|
83
116
|
You can delete all the data stored by Eyeloupe by clicking on the trash button.
|
|
84
117
|
|
|
118
|
+
### AI Assistant
|
|
119
|
+
|
|
120
|
+
When you define an OpenAI access key in the configuration, you could see a new section in the exception details page. This section is powered by the OpenAI API and it's able to give you a solution to solve your exception.
|
|
121
|
+
It sends the entire content of the file containing the exception to have the best answer to your problem.
|
|
122
|
+
|
|
123
|
+

|
|
124
|
+
|
|
125
|
+
## Upgrade
|
|
126
|
+
|
|
127
|
+
When your upgrade Eyeloupe to the latest version, be sure to run the following commands:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
$ rails eyeloupe:install:migrations
|
|
131
|
+
$ rails db:migrate
|
|
132
|
+
```
|
|
85
133
|
|
|
86
134
|
## Q/A
|
|
87
135
|
|
|
@@ -95,8 +143,10 @@ Yes, Eyeloupe is inspired by Laravel Telescope. A lot of people coming from Lara
|
|
|
95
143
|
|
|
96
144
|
## Roadmap
|
|
97
145
|
|
|
98
|
-
- [
|
|
146
|
+
- [x] Exceptions - Track all the exceptions thrown by your application
|
|
147
|
+
- [x] AI assistant - Use OpenAI API to help you to solve your exceptions
|
|
99
148
|
- [ ] Custom links to the menu - To access all of your debug tool in one place (Sidekiq web, Mailhog, etc.)
|
|
149
|
+
- [ ] Refactoring / clean code - To make the code more readable and maintainable
|
|
100
150
|
|
|
101
151
|
## Contributing
|
|
102
152
|
Contributions are what makes the open-source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
|
@@ -135,4 +185,4 @@ Project Link: [https://github.com/alxlion/eyeloupe](https://github.com/alxlion/e
|
|
|
135
185
|
[license-url]: https://github.com/alxlion/eyeloupe/blob/master/MIT-LICENSE.txt
|
|
136
186
|
[eyeloupe-screen]: /doc/img/screen.png
|
|
137
187
|
[gem-version]: https://badge.fury.io/rb/eyeloupe.svg
|
|
138
|
-
[gem-url]: https://rubygems.org/gems/eyeloupe
|
|
188
|
+
[gem-url]: https://rubygems.org/gems/eyeloupe
|
|
@@ -1 +1 @@
|
|
|
1
|
-
/*! tailwindcss v3.1.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:Fira Sans,sans-serif,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select{color-adjust:exact;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact}[multiple]{color-adjust:unset;background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset}[type=checkbox],[type=radio]{color-adjust:exact;--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:#6b7280;border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:#0000}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:#0000}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:#0000}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px auto -webkit-focus-ring-color}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:-webkit-sticky;position:sticky}.inset-0{bottom:0;left:0;right:0;top:0}.left-full{left:100%}.top-0{top:0}.z-50{z-index:50}.z-40{z-index:40}.-m-2\.5{margin:-.625rem}.-m-2{margin:-.5rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.-my-2{margin-bottom:-.5rem;margin-top:-.5rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mt-4{margin-top:1rem}.mt-2{margin-top:.5rem}.mt-8{margin-top:2rem}.mt-6{margin-top:1.5rem}.mt-1{margin-top:.25rem}.mr-16{margin-right:4rem}.ml-2{margin-left:.5rem}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.flow-root{display:flow-root}.hidden{display:none}.h-6{height:1.5rem}.h-16{height:4rem}.h-7{height:1.75rem}.h-12{height:3rem}.h-5{height:1.25rem}.w-full{width:100%}.w-16{width:4rem}.w-6{width:1.5rem}.w-auto{width:auto}.w-5{width:1.25rem}.min-w-full{min-width:100%}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.flex-col{flex-direction:column}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-y-5{row-gap:1.25rem}.gap-y-7{row-gap:1.75rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-300>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(209 213 219/var(--tw-divide-opacity))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-t{border-top-width:1px}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(250 245 255/var(--tw-bg-opacity))}.bg-gray-900\/80{background-color:#111827cc}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-1{padding:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-bottom:1.25rem;padding-top:1.25rem}.pl-4{padding-left:1rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.pr-4{padding-right:1rem}.pt-5{padding-top:1.25rem}.pb-2{padding-bottom:.5rem}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-2xl{font-size:1.5rem;line-height:2rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.tracking-wide{letter-spacing:.025em}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(133 77 14/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-purple-700{--tw-text-opacity:1;color:rgb(126 34 206/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.ring-green-600\/20{--tw-ring-color:#16a34a33}.ring-blue-700\/10{--tw-ring-color:#1d4ed81a}.ring-yellow-600\/20{--tw-ring-color:#ca8a0433}.ring-red-600\/10{--tw-ring-color:#dc26261a}.ring-gray-500\/10{--tw-ring-color:#6b72801a}.ring-gray-500{--tw-ring-opacity:1;--tw-ring-color:rgb(107 114 128/var(--tw-ring-opacity))}.ring-purple-700\/10{--tw-ring-color:#7e22ce1a}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-500{transition-duration:.5s}.pagination{display:inline-flex;position:relative;z-index:0}.pagination>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1px*var(--tw-space-x-reverse))}.pagination{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.pagination .prev a{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-bottom-left-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-left-radius:.375rem;border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;padding:.5rem;position:relative}.pagination .prev a:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .next a{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-bottom-right-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-right-radius:.375rem;border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;padding:.5rem;position:relative}.pagination .next a:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .current{--tw-text-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity));border-top-width:2px;color:rgb(239 68 68/var(--tw-text-opacity));padding-left:1rem;padding-right:1rem;padding-top:1rem}.pagination .current,.pagination a{--tw-border-opacity:1;align-items:center;display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem}.pagination a{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-color:rgb(209 213 219/var(--tw-border-opacity));border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));padding:.5rem 1rem;position:relative}.pagination a:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .disabled{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-color:rgb(209 213 219/var(--tw-border-opacity));border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;opacity:.4;padding:.5rem 1rem;position:relative}.pagination .disabled:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .gap{background-color:rgb(255 255 255/var(--tw-bg-opacity));border-color:rgb(209 213 219/var(--tw-border-opacity));color:rgb(55 65 81/var(--tw-text-opacity))}.pagination .active,.pagination .gap{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;border-width:1px;display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;padding:.5rem 1rem;position:relative}.pagination .active{background-color:rgb(254 242 242/var(--tw-bg-opacity));border-color:rgb(239 68 68/var(--tw-border-opacity));color:rgb(239 68 68/var(--tw-text-opacity));z-index:10}.pagination .next_page,.pagination .previous_page{display:none}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(239 68 68/var(--tw-ring-opacity))}@media (min-width:640px){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mt-0{margin-top:0}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:flex-auto{flex:1 1 auto}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:gap-4{gap:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:px-0{padding-right:0}.sm\:pl-0,.sm\:px-0{padding-left:0}.sm\:pr-0{padding-right:0}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:1024px){.lg\:fixed{position:fixed}.lg\:inset-y-0{bottom:0;top:0}.lg\:z-50{z-index:50}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-72{width:18rem}.lg\:flex-col{flex-direction:column}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pl-72{padding-left:18rem}}
|
|
1
|
+
/*! tailwindcss v3.1.3 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:Fira Sans,sans-serif,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,select:focus,textarea:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}select{color-adjust:exact;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact}[multiple]{color-adjust:unset;background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset}[type=checkbox],[type=radio]{color-adjust:exact;--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:#6b7280;border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid #0000;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:#0000}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3E%3C/svg%3E")}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=checkbox]:indeterminate,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:#0000}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:#0000}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px auto -webkit-focus-ring-color}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:-webkit-sticky;position:sticky}.inset-0{bottom:0;left:0;right:0;top:0}.left-full{left:100%}.top-0{top:0}.z-50{z-index:50}.z-40{z-index:40}.col-span-1{grid-column:span 1/span 1}.col-span-11{grid-column:span 11/span 11}.-m-2\.5{margin:-.625rem}.-m-2{margin:-.5rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.-my-2{margin-bottom:-.5rem;margin-top:-.5rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mt-4{margin-top:1rem}.mt-2{margin-top:.5rem}.mt-8{margin-top:2rem}.mt-6{margin-top:1.5rem}.mt-1{margin-top:.25rem}.mr-16{margin-right:4rem}.ml-2{margin-left:.5rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.flow-root{display:flow-root}.grid{display:grid}.hidden{display:none}.h-6{height:1.5rem}.h-16{height:4rem}.h-7{height:1.75rem}.h-12{height:3rem}.h-5{height:1.25rem}.w-full{width:100%}.w-16{width:4rem}.w-6{width:1.5rem}.w-auto{width:auto}.w-5{width:1.25rem}.min-w-full{min-width:100%}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.flex-col{flex-direction:column}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-y-5{row-gap:1.25rem}.gap-y-7{row-gap:1.75rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-300>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(209 213 219/var(--tw-divide-opacity))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(243 244 246/var(--tw-divide-opacity))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-t{border-top-width:1px}.border-b{border-bottom-width:1px}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity))}.bg-yellow-50{--tw-bg-opacity:1;background-color:rgb(254 252 232/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-purple-50{--tw-bg-opacity:1;background-color:rgb(250 245 255/var(--tw-bg-opacity))}.bg-gray-900\/80{background-color:#111827cc}.bg-opacity-30{--tw-bg-opacity:0.3}.p-2{padding:.5rem}.\!p-0{padding:0!important}.p-2\.5{padding:.625rem}.p-1{padding:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-5{padding-bottom:1.25rem;padding-top:1.25rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-0{padding-left:0;padding-right:0}.py-1{padding-bottom:.25rem;padding-top:.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.pl-4{padding-left:1rem}.pr-3{padding-right:.75rem}.pl-3{padding-left:.75rem}.pr-4{padding-right:1rem}.pt-2{padding-top:.5rem}.pb-4{padding-bottom:1rem}.pb-3{padding-bottom:.75rem}.pt-5{padding-top:1.25rem}.pb-2{padding-bottom:.5rem}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-2xl{font-size:1.5rem;line-height:2rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.tracking-wide{letter-spacing:.025em}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-green-700{--tw-text-opacity:1;color:rgb(21 128 61/var(--tw-text-opacity))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity))}.text-yellow-800{--tw-text-opacity:1;color:rgb(133 77 14/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-purple-700{--tw-text-opacity:1;color:rgb(126 34 206/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.underline{-webkit-text-decoration-line:underline;text-decoration-line:underline}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-inset{--tw-ring-inset:inset}.ring-green-600\/20{--tw-ring-color:#16a34a33}.ring-blue-700\/10{--tw-ring-color:#1d4ed81a}.ring-yellow-600\/20{--tw-ring-color:#ca8a0433}.ring-red-600\/10{--tw-ring-color:#dc26261a}.ring-gray-500\/10{--tw-ring-color:#6b72801a}.ring-gray-500{--tw-ring-opacity:1;--tw-ring-color:rgb(107 114 128/var(--tw-ring-opacity))}.ring-purple-700\/10{--tw-ring-color:#7e22ce1a}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-text-decoration-color,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-500{transition-duration:.5s}.pagination{display:inline-flex;position:relative;z-index:0}.pagination>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1px*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1px*var(--tw-space-x-reverse))}.pagination{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);border-radius:.375rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.pagination .prev a{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-bottom-left-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-left-radius:.375rem;border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;padding:.5rem;position:relative}.pagination .prev a:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .next a{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-bottom-right-radius:.375rem;border-color:rgb(209 213 219/var(--tw-border-opacity));border-top-right-radius:.375rem;border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;padding:.5rem;position:relative}.pagination .next a:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .current{--tw-text-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity));border-top-width:2px;color:rgb(239 68 68/var(--tw-text-opacity));padding-left:1rem;padding-right:1rem;padding-top:1rem}.pagination .current,.pagination a{--tw-border-opacity:1;align-items:center;display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem}.pagination a{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-color:rgb(209 213 219/var(--tw-border-opacity));border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));padding:.5rem 1rem;position:relative}.pagination a:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .disabled{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity));border-color:rgb(209 213 219/var(--tw-border-opacity));border-width:1px;color:rgb(107 114 128/var(--tw-text-opacity));display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;opacity:.4;padding:.5rem 1rem;position:relative}.pagination .disabled:hover{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.pagination .gap{background-color:rgb(255 255 255/var(--tw-bg-opacity));border-color:rgb(209 213 219/var(--tw-border-opacity));color:rgb(55 65 81/var(--tw-text-opacity))}.pagination .active,.pagination .gap{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-text-opacity:1;align-items:center;border-width:1px;display:inline-flex;font-size:.875rem;font-weight:500;line-height:1.25rem;padding:.5rem 1rem;position:relative}.pagination .active{background-color:rgb(254 242 242/var(--tw-bg-opacity));border-color:rgb(239 68 68/var(--tw-border-opacity));color:rgb(239 68 68/var(--tw-text-opacity));z-index:10}.pagination .next_page,.pagination .previous_page{display:none}#result pre{background-color:rgb(0 0 0/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));margin-bottom:.5rem;margin-top:.5rem;padding:.75rem}#result p code,#result pre{--tw-bg-opacity:1;--tw-text-opacity:1;border-radius:.375rem}#result p code{background-color:rgb(229 231 235/var(--tw-bg-opacity));color:rgb(75 85 99/var(--tw-text-opacity));font-size:.875rem;line-height:1.25rem;padding:.125rem .5rem}.hover\:bg-red-600:hover{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity))}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-red-400:hover{--tw-bg-opacity:1;background-color:rgb(248 113 113/var(--tw-bg-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:border-red-500:focus{--tw-border-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(239 68 68/var(--tw-ring-opacity))}@media (min-width:640px){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:mt-0{margin-top:0}.sm\:flex{display:flex}.sm\:grid{display:grid}.sm\:flex-auto{flex:1 1 auto}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:gap-4{gap:1rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:px-0{padding-right:0}.sm\:pl-0,.sm\:px-0{padding-left:0}.sm\:pr-0{padding-right:0}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:1024px){.lg\:fixed{position:fixed}.lg\:inset-y-0{bottom:0;top:0}.lg\:z-50{z-index:50}.lg\:-mx-8{margin-left:-2rem;margin-right:-2rem}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:w-72{width:18rem}.lg\:flex-col{flex-direction:column}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pl-72{padding-left:18rem}}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import showdown from "showdown"
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["result", "loader", "btn"]
|
|
5
|
+
static values = { url: String }
|
|
6
|
+
|
|
7
|
+
assist() {
|
|
8
|
+
this.btnTarget.classList.add("hidden")
|
|
9
|
+
this.resultTarget.innerHTML = ""
|
|
10
|
+
this.loaderTarget.classList.remove("hidden")
|
|
11
|
+
|
|
12
|
+
fetch(this.urlValue)
|
|
13
|
+
.then(response => response.json())
|
|
14
|
+
.then(json => {
|
|
15
|
+
let result = json.choices[0].message.content
|
|
16
|
+
let converter = new showdown.Converter()
|
|
17
|
+
this.resultTarget.innerHTML = converter.makeHtml(result)
|
|
18
|
+
|
|
19
|
+
})
|
|
20
|
+
.catch(error => {
|
|
21
|
+
this.resultTarget.innerHTML = error
|
|
22
|
+
})
|
|
23
|
+
.finally(() => {
|
|
24
|
+
this.loaderTarget.classList.add("hidden")
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -39,4 +39,12 @@
|
|
|
39
39
|
|
|
40
40
|
.pagination .previous_page, .pagination .next_page {
|
|
41
41
|
@apply hidden;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#result pre {
|
|
45
|
+
@apply bg-black text-white p-3 rounded-md my-2;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#result p code {
|
|
49
|
+
@apply bg-gray-200 text-gray-600 px-2 py-0.5 text-sm rounded-md;
|
|
42
50
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Eyeloupe
|
|
4
|
+
class AiAssistantResponsesController < ApplicationController
|
|
5
|
+
|
|
6
|
+
before_action :set_exception, only: %i[ show ]
|
|
7
|
+
|
|
8
|
+
def show
|
|
9
|
+
client = OpenAI::Client.new
|
|
10
|
+
|
|
11
|
+
code = File.read(@exception.file)
|
|
12
|
+
|
|
13
|
+
@response = client.chat(
|
|
14
|
+
parameters: {
|
|
15
|
+
model: Eyeloupe::configuration.openai_model,
|
|
16
|
+
messages: [{"role": "system", "content": "You are a Ruby on Rails software developer, you develop software programs and applications using programming languages like Ruby and Ruby on Rails and development tools."},
|
|
17
|
+
{"role": "user", "content": "I have a problem with my Ruby on Rails application. I am getting an error message that says: #{@exception.kind} #{@exception.message}. Here is my code, the error is in line #{@exception.line}: #{code}. Answer as concise as possible. Show me resulting code. The response should in Markdown format."}],
|
|
18
|
+
temperature: 0.7
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
render json: @response
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def set_exception
|
|
27
|
+
@exception = Exception.find(params[:id])
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Eyeloupe
|
|
4
|
+
class ExceptionsController < ApplicationController
|
|
5
|
+
|
|
6
|
+
before_action :set_exception, only: %i[ show ]
|
|
7
|
+
|
|
8
|
+
# GET /out_requests
|
|
9
|
+
def index
|
|
10
|
+
@pagy, @exceptions = pagy(Exception.all.order(created_at: :desc), items: 50)
|
|
11
|
+
|
|
12
|
+
render partial: 'frame' if params[:frame].present?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /out_requests/1
|
|
16
|
+
def show
|
|
17
|
+
start = @exception.line - 5
|
|
18
|
+
start = 0 if start < 0
|
|
19
|
+
@line_numbers = [*start..@exception.line+6]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
# Use callbacks to share common setup or constraints between actions.
|
|
24
|
+
def set_exception
|
|
25
|
+
@exception = Exception.find(params[:id])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
module Eyeloupe
|
|
2
2
|
class ApplicationRecord < ActiveRecord::Base
|
|
3
3
|
self.abstract_class = true
|
|
4
|
+
|
|
5
|
+
if Eyeloupe.configuration.database
|
|
6
|
+
connects_to database: { writing: Eyeloupe.configuration.database.to_sym, reading: Eyeloupe.configuration.database.to_sym }
|
|
7
|
+
end
|
|
4
8
|
end
|
|
5
9
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<%= turbo_frame_tag "frame" do %>
|
|
2
|
+
<div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
|
3
|
+
<div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
|
4
|
+
|
|
5
|
+
<table class="min-w-full divide-y divide-gray-300">
|
|
6
|
+
<thead>
|
|
7
|
+
<tr>
|
|
8
|
+
<th scope="col" class="py-3 pl-4 pr-3 text-left text-sm font-medium uppercase tracking-wide text-gray-500 sm:pl-0">Kind</th>
|
|
9
|
+
<th scope="col" class="px-3 py-3 text-left text-sm font-medium uppercase tracking-wide text-gray-500">Count</th>
|
|
10
|
+
<th scope="col" class="px-3 py-3 text-left text-sm font-medium uppercase tracking-wide text-gray-500">Occured</th>
|
|
11
|
+
<th scope="col" class="relative py-3 pl-3 pr-4 sm:pr-0">
|
|
12
|
+
<span class="sr-only">Details</span>
|
|
13
|
+
</th>
|
|
14
|
+
</tr>
|
|
15
|
+
</thead>
|
|
16
|
+
<tbody class="divide-y divide-gray-200">
|
|
17
|
+
<% @exceptions.each do |ex| %>
|
|
18
|
+
<tr>
|
|
19
|
+
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-base font-medium text-gray-900 sm:pl-0">
|
|
20
|
+
<%= ex.kind %>
|
|
21
|
+
<p class="text-sm font-normal text-gray-500"><%= ex.message.truncate(100) %></p>
|
|
22
|
+
</td>
|
|
23
|
+
<td class="whitespace-nowrap px-3 py-4 text-base text-gray-500"><%= ex.count %></td>
|
|
24
|
+
<td class="whitespace-nowrap px-3 py-4 text-base text-gray-500"><%= distance_of_time_in_words(ex.updated_at, DateTime.now) %></td>
|
|
25
|
+
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-base font-medium sm:pr-0">
|
|
26
|
+
<%= link_to "Details", exception_path(ex), class: "text-gray-600 hover:text-gray-900", data: {"turbo_frame": "_top"} %>
|
|
27
|
+
</td>
|
|
28
|
+
</tr>
|
|
29
|
+
<% end %>
|
|
30
|
+
</tbody>
|
|
31
|
+
</table>
|
|
32
|
+
</div>
|
|
33
|
+
<aside class="mt-4 px-4 py-3 flex items-center justify-center sm:px-6" aria-label="Pagination">
|
|
34
|
+
<div class="flex-1 flex justify-center">
|
|
35
|
+
<%== pagy_nav(@pagy) %>
|
|
36
|
+
</div>
|
|
37
|
+
</aside>
|
|
38
|
+
</div>
|
|
39
|
+
<% end %>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<div class="px-4 sm:px-6 lg:px-8 bg-white rounded-md shadow-md py-5">
|
|
2
|
+
<div class="sm:flex sm:items-center">
|
|
3
|
+
<div class="sm:flex-auto">
|
|
4
|
+
<h1 class="text-xl font-semibold leading-6 text-gray-900">Exceptions</h1>
|
|
5
|
+
<p class="mt-2 text-sm text-gray-700">All exceptions that have been raised in the application.</p>
|
|
6
|
+
</div>
|
|
7
|
+
<div>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="mt-8 flow-root">
|
|
11
|
+
<%= turbo_frame_tag "frame", src: exceptions_path(frame: true), data: {"eyeloupe--refresh-target": "frame"} do %><% end %>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<div class="px-4 sm:px-6 lg:px-8 bg-white rounded-md shadow-md py-5">
|
|
2
|
+
<div class="px-4 sm:px-0">
|
|
3
|
+
<h3 class="text-xl font-semibold leading-7 text-gray-900">Exception Details</h3>
|
|
4
|
+
</div>
|
|
5
|
+
<div class="mt-6 border-t border-gray-100">
|
|
6
|
+
<dl class="divide-y divide-gray-100">
|
|
7
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
8
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Time</dt>
|
|
9
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
|
10
|
+
<%= @exception.created_at.to_formatted_s(:long) %> (<%= distance_of_time_in_words(@exception.updated_at, DateTime.now) %>)
|
|
11
|
+
</dd>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
14
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Hostname</dt>
|
|
15
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0"><%= @exception.hostname %></dd>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
18
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Kind</dt>
|
|
19
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
|
20
|
+
<%= @exception.kind %>
|
|
21
|
+
</dd>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
24
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Count</dt>
|
|
25
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
|
26
|
+
<%= @exception.count %>
|
|
27
|
+
</dd>
|
|
28
|
+
</div>
|
|
29
|
+
<% if @exception.in_request_id.present? %>
|
|
30
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
31
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Request</dt>
|
|
32
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
|
33
|
+
<%= link_to "View request", in_request_path(@exception.in_request_id), class: "underline" %>
|
|
34
|
+
</dd>
|
|
35
|
+
</div>
|
|
36
|
+
<% end %>
|
|
37
|
+
<% if @exception.out_request_id.present? %>
|
|
38
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
39
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Request</dt>
|
|
40
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
|
41
|
+
<%= link_to "View request", out_request_path(@exception.out_request_id), class: "underline" %>
|
|
42
|
+
</dd>
|
|
43
|
+
</div>
|
|
44
|
+
<% end %>
|
|
45
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
46
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Message</dt>
|
|
47
|
+
<dd class="mt-1 text-base leading-6 sm:col-span-2 sm:mt-0 rounded-md bg-black text-white overflow-x-auto">
|
|
48
|
+
<pre class="p-2"><%= @exception.message %></pre>
|
|
49
|
+
</dd>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
52
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Backtrace</dt>
|
|
53
|
+
<dd class="mt-1 text-base leading-6 sm:col-span-2 sm:mt-0 rounded-md bg-black text-white overflow-x-auto">
|
|
54
|
+
<pre class="p-2"><%= JSON.parse(@exception.stacktrace).join("\n") %></pre>
|
|
55
|
+
</dd>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
58
|
+
<dt class="text-base font-medium leading-6 text-gray-900">Code preview</dt>
|
|
59
|
+
<dd class="mt-1 text-base leading-6 sm:col-span-2 sm:mt-0 rounded-md bg-black text-white overflow-x-auto px-2 pt-2">
|
|
60
|
+
<p class="pb-4 font-semibold"><%= @exception.file %></p>
|
|
61
|
+
<% JSON.parse(@exception.location).each_with_index do |line, i| %>
|
|
62
|
+
<div class="grid grid-cols-12 gap-x-1 <%= @line_numbers[i] + 1 == @exception.line ? "bg-red-500 bg-opacity-30" : "" %>">
|
|
63
|
+
<span class="text-right col-span-1 font-medium text-base text-gray-300"><%= @line_numbers[i] + 1 %></span>
|
|
64
|
+
<pre class="col-span-11"><code class="!p-0"><%= line %></code></pre>
|
|
65
|
+
</div>
|
|
66
|
+
<% end %>
|
|
67
|
+
</dd>
|
|
68
|
+
</div>
|
|
69
|
+
<% if Eyeloupe::configuration.openai_access_key.present? %>
|
|
70
|
+
<div class="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0" data-controller="eyeloupe--ai-assistant" data-eyeloupe--ai-assistant-url-value="<%= ai_assistant_response_url(@exception) %>">
|
|
71
|
+
<dt class="text-base font-medium leading-6 text-gray-900">AI Assistant</dt>
|
|
72
|
+
<dd class="mt-1 text-base leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
|
73
|
+
<button data-action="eyeloupe--ai-assistant#assist" data-eyeloupe--ai-assistant-target="btn" class="rounded-md px-2 py-1 text-white bg-red-500 text-xl hover:shadow-md hover:bg-red-400 transition flex gap-x-2">
|
|
74
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-robot" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
75
|
+
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
76
|
+
<path d="M7 7h10a2 2 0 0 1 2 2v1l1 1v3l-1 1v3a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-3l-1 -1v-3l1 -1v-1a2 2 0 0 1 2 -2z"></path>
|
|
77
|
+
<path d="M10 16h4"></path>
|
|
78
|
+
<circle cx="8.5" cy="11.5" r=".5" fill="currentColor"></circle>
|
|
79
|
+
<circle cx="15.5" cy="11.5" r=".5" fill="currentColor"></circle>
|
|
80
|
+
<path d="M9 7l-1 -4"></path>
|
|
81
|
+
<path d="M15 7l1 -4"></path>
|
|
82
|
+
</svg>
|
|
83
|
+
<span>Click to get some help</span>
|
|
84
|
+
</button>
|
|
85
|
+
|
|
86
|
+
<svg data-eyeloupe--ai-assistant-target="loader" width="50" class="hidden" viewBox="0 0 120 30" xmlns="http://www.w3.org/2000/svg" fill="#ff3130">
|
|
87
|
+
<circle cx="15" cy="15" r="15">
|
|
88
|
+
<animate attributeName="r" from="15" to="15"
|
|
89
|
+
begin="0s" dur="0.8s"
|
|
90
|
+
values="15;9;15" calcMode="linear"
|
|
91
|
+
repeatCount="indefinite" />
|
|
92
|
+
<animate attributeName="fill-opacity" from="1" to="1"
|
|
93
|
+
begin="0s" dur="0.8s"
|
|
94
|
+
values="1;.5;1" calcMode="linear"
|
|
95
|
+
repeatCount="indefinite" />
|
|
96
|
+
</circle>
|
|
97
|
+
<circle cx="60" cy="15" r="9" fill-opacity="0.3">
|
|
98
|
+
<animate attributeName="r" from="9" to="9"
|
|
99
|
+
begin="0s" dur="0.8s"
|
|
100
|
+
values="9;15;9" calcMode="linear"
|
|
101
|
+
repeatCount="indefinite" />
|
|
102
|
+
<animate attributeName="fill-opacity" from="0.5" to="0.5"
|
|
103
|
+
begin="0s" dur="0.8s"
|
|
104
|
+
values=".5;1;.5" calcMode="linear"
|
|
105
|
+
repeatCount="indefinite" />
|
|
106
|
+
</circle>
|
|
107
|
+
<circle cx="105" cy="15" r="15">
|
|
108
|
+
<animate attributeName="r" from="15" to="15"
|
|
109
|
+
begin="0s" dur="0.8s"
|
|
110
|
+
values="15;9;15" calcMode="linear"
|
|
111
|
+
repeatCount="indefinite" />
|
|
112
|
+
<animate attributeName="fill-opacity" from="1" to="1"
|
|
113
|
+
begin="0s" dur="0.8s"
|
|
114
|
+
values="1;.5;1" calcMode="linear"
|
|
115
|
+
repeatCount="indefinite" />
|
|
116
|
+
</circle>
|
|
117
|
+
</svg>
|
|
118
|
+
|
|
119
|
+
<p data-eyeloupe--ai-assistant-target="result" id="result"></p>
|
|
120
|
+
</dd>
|
|
121
|
+
</div>
|
|
122
|
+
<% end %>
|
|
123
|
+
</dl>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
</div>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-base font-medium text-gray-900 sm:pl-0">
|
|
22
22
|
<%= render "eyeloupe/shared/verb", verb: request.verb %>
|
|
23
23
|
</td>
|
|
24
|
-
<td class="whitespace-nowrap px-3 py-4 text-base text-gray-500"><%= request.path.truncate(
|
|
24
|
+
<td class="whitespace-nowrap px-3 py-4 text-base text-gray-500"><%= request.path.truncate(100) %></td>
|
|
25
25
|
<td class="whitespace-nowrap px-3 py-4 text-base text-gray-500">
|
|
26
26
|
<%= render "eyeloupe/shared/status_code", code: request.status %>
|
|
27
27
|
</td>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<div data-controller="eyeloupe--search">
|
|
1
|
+
<div data-controller="eyeloupe--search" class="px-4 sm:px-6 lg:px-8 bg-white rounded-md shadow-md py-5">
|
|
2
2
|
<div class="sm:flex sm:items-center">
|
|
3
3
|
<div class="sm:flex-auto">
|
|
4
4
|
<h1 class="text-xl font-semibold leading-6 text-gray-900">Requests</h1>
|