tybo 0.6.1 → 0.7.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/app/assets/config/tybo_manifest.js +1 -0
- data/app/assets/images/cover.svg +36 -0
- data/app/assets/images/logo.svg +10 -0
- data/app/assets/javascripts/tybo/controllers/attachments_controller.js +13 -0
- data/app/assets/javascripts/tybo/controllers/dropdown_controller.js +15 -0
- data/app/assets/javascripts/tybo/controllers/flash_controller.js +7 -0
- data/app/assets/javascripts/tybo/controllers/index.js +7 -0
- data/app/assets/javascripts/tybo/controllers/questions_controller.js +62 -0
- data/app/assets/javascripts/tybo/controllers/search_form_controller.js +34 -0
- data/app/assets/javascripts/tybo/controllers/sidebar_controller.js +16 -0
- data/app/assets/javascripts/tybo/controllers/ts/search_controller.js +29 -0
- data/app/assets/javascripts/tybo/controllers/ts/select_controller.js +8 -0
- data/app/components/attachment_card_component.html.erb +1 -1
- data/app/components/forms/search_date_input_component.html.erb +2 -2
- data/app/components/sidebar_component.html.erb +5 -5
- data/app/views/layouts/_errors.html.erb +2 -2
- data/app/views/layouts/_flash.html.erb +2 -2
- data/app/views/layouts/devise_admin.html.erb +3 -2
- data/config/importmap.rb +0 -0
- data/lib/generators/bo/templates/_form.html.erb +1 -1
- data/lib/generators/bo/templates/_search_bar.html.erb +11 -11
- data/lib/generators/bo_namespace/bo_namespace_generator.rb +1 -1
- data/lib/generators/bo_namespace/templates/admin.html.erb +2 -4
- data/lib/generators/tybo_install/templates/application_tybo_admin.js +20 -0
- data/lib/generators/tybo_install/templates/tybo_admin.tailwind.css +112 -0
- data/lib/generators/tybo_install/templates/tybo_config.rb +1 -1
- data/lib/generators/tybo_install/tybo_install_generator.rb +29 -9
- data/lib/generators/tybo_install/utils/translations.rb +35 -2
- data/lib/generators/tybo_upgrade/tybo_upgrade_generator.rb +193 -0
- data/lib/puma/plugin/tybo.rb +36 -0
- data/lib/tasks/tybo.rake +46 -0
- data/lib/tybo/engine.rb +4 -0
- data/lib/tybo/version.rb +1 -1
- metadata +18 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ebad2a70d38a84816f82190a77c32ff5a2cd10477757176304fc6e1e399c8713
|
|
4
|
+
data.tar.gz: f6a70f5f02ef98faf6fa371a4771151741ffbd6a3134e9dc4a56d3ac754f9251
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a931cec4abad743ce1996da98fe63332f9cf30eba3c647d16cb931abecedc452355a0fdf48e64a5d2a4db7aaf5d46961bd7199a1527e774bb697af8acc1d5595
|
|
7
|
+
data.tar.gz: 8a20e59bfdf5db506a27494ed540a81ef5ef51d9b50b20c7cd50b65f8799e0fbd2bb2e226496679f5bb88cdcfbd04d45d690caefe10ede25fa4ec17cf38809a9
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600" fill="none">
|
|
2
|
+
<!-- Background gradient -->
|
|
3
|
+
<defs>
|
|
4
|
+
<linearGradient id="bg" x1="0" y1="0" x2="800" y2="600" gradientUnits="userSpaceOnUse">
|
|
5
|
+
<stop offset="0%" stop-color="#3b0764"/>
|
|
6
|
+
<stop offset="100%" stop-color="#581c87"/>
|
|
7
|
+
</linearGradient>
|
|
8
|
+
<linearGradient id="glow" x1="0" y1="0" x2="1" y2="1">
|
|
9
|
+
<stop offset="0%" stop-color="#c084fc" stop-opacity="0.3"/>
|
|
10
|
+
<stop offset="100%" stop-color="#581c87" stop-opacity="0"/>
|
|
11
|
+
</linearGradient>
|
|
12
|
+
</defs>
|
|
13
|
+
|
|
14
|
+
<rect width="800" height="600" fill="url(#bg)"/>
|
|
15
|
+
|
|
16
|
+
<!-- Decorative circles -->
|
|
17
|
+
<circle cx="650" cy="100" r="200" fill="url(#glow)"/>
|
|
18
|
+
<circle cx="150" cy="500" r="150" fill="url(#glow)"/>
|
|
19
|
+
|
|
20
|
+
<!-- Grid lines subtle -->
|
|
21
|
+
<line x1="0" y1="150" x2="800" y2="150" stroke="#c084fc" stroke-opacity="0.08" stroke-width="1"/>
|
|
22
|
+
<line x1="0" y1="300" x2="800" y2="300" stroke="#c084fc" stroke-opacity="0.08" stroke-width="1"/>
|
|
23
|
+
<line x1="0" y1="450" x2="800" y2="450" stroke="#c084fc" stroke-opacity="0.08" stroke-width="1"/>
|
|
24
|
+
<line x1="200" y1="0" x2="200" y2="600" stroke="#c084fc" stroke-opacity="0.08" stroke-width="1"/>
|
|
25
|
+
<line x1="400" y1="0" x2="400" y2="600" stroke="#c084fc" stroke-opacity="0.08" stroke-width="1"/>
|
|
26
|
+
<line x1="600" y1="0" x2="600" y2="600" stroke="#c084fc" stroke-opacity="0.08" stroke-width="1"/>
|
|
27
|
+
|
|
28
|
+
<!-- Logo text -->
|
|
29
|
+
<text x="400" y="290" font-family="ui-sans-serif, system-ui, sans-serif" font-size="96" font-weight="700" fill="white" text-anchor="middle" letter-spacing="-3" opacity="0.95">tybo</text>
|
|
30
|
+
|
|
31
|
+
<!-- Tagline -->
|
|
32
|
+
<text x="400" y="340" font-family="ui-sans-serif, system-ui, sans-serif" font-size="18" fill="#c084fc" text-anchor="middle" letter-spacing="4" opacity="0.8">ADMIN FRAMEWORK</text>
|
|
33
|
+
|
|
34
|
+
<!-- Accent dot -->
|
|
35
|
+
<circle cx="530" cy="228" r="8" fill="#c084fc" opacity="0.9"/>
|
|
36
|
+
</svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 48" fill="none">
|
|
2
|
+
<!-- Background pill -->
|
|
3
|
+
<rect width="160" height="48" rx="12" fill="#581c87"/>
|
|
4
|
+
|
|
5
|
+
<!-- T -->
|
|
6
|
+
<text x="16" y="34" font-family="ui-sans-serif, system-ui, sans-serif" font-size="28" font-weight="700" fill="white" letter-spacing="-1">tybo</text>
|
|
7
|
+
|
|
8
|
+
<!-- Accent dot -->
|
|
9
|
+
<circle cx="144" cy="12" r="5" fill="#c084fc"/>
|
|
10
|
+
</svg>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import { FetchRequest } from '@rails/request.js'
|
|
3
|
+
|
|
4
|
+
export default class extends Controller {
|
|
5
|
+
static values = { url: String, method: String, attachmentId: Number }
|
|
6
|
+
|
|
7
|
+
async toggle(event) {
|
|
8
|
+
event.preventDefault()
|
|
9
|
+
|
|
10
|
+
const request = new FetchRequest(this.methodValue, this.urlValue, { responseKind: "turbo-stream", body: { attachment_id: this.attachmentIdValue } })
|
|
11
|
+
await request.perform()
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["menu"]
|
|
5
|
+
|
|
6
|
+
toggle() {
|
|
7
|
+
this.menuTarget.classList.toggle("hidden")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
hide(event) {
|
|
11
|
+
if (!this.element.contains(event.target) && !this.menuTarget.classList.contains('hidden')) {
|
|
12
|
+
this.menuTarget.classList.add("hidden")
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as Attachments } from "./attachments_controller.js";
|
|
2
|
+
export { default as Dropdown } from "./dropdown_controller.js";
|
|
3
|
+
export { default as Flash } from "./flash_controller.js";
|
|
4
|
+
export { default as SearchForm } from "./search_form_controller.js";
|
|
5
|
+
export { default as TsSearch } from "./ts/search_controller.js";
|
|
6
|
+
export { default as TsSelect } from "./ts/select_controller.js";
|
|
7
|
+
export { default as Sidebar } from "./sidebar_controller.js";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ['questionKind', 'questionType', 'newQuestion', 'choices', 'documentType']
|
|
5
|
+
|
|
6
|
+
changeType(e) {
|
|
7
|
+
let questionType = e.target.selectedOptions[0].value
|
|
8
|
+
let kindInput = this.questionKindTarget
|
|
9
|
+
this.getKindInput(questionType, kindInput)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getKindInput(questionType, kindInput) {
|
|
13
|
+
fetch(`/admin/questions/kinds?type=${questionType}`, {
|
|
14
|
+
method: 'GET',
|
|
15
|
+
}).then(response => response.json())
|
|
16
|
+
.then(data => {
|
|
17
|
+
kindInput.options.length = 0
|
|
18
|
+
data.unshift('')
|
|
19
|
+
for (let i in data) {
|
|
20
|
+
kindInput.options[kindInput.options.length] = new Option(data[i][0], data[i][1]);
|
|
21
|
+
}
|
|
22
|
+
this.displayChoiceBtn()
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
changeKind() {
|
|
27
|
+
this.displayChoiceBtn()
|
|
28
|
+
this.removeChoices()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
removeChoices() {
|
|
32
|
+
document.getElementById('choices').innerHTML = ''
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
updateChoicePartial() {
|
|
36
|
+
let questionKind = this.questionKindTarget.selectedOptions[0].value
|
|
37
|
+
let questionType = this.questionTypeTarget.selectedOptions[0].value
|
|
38
|
+
let choices = this.choicesTarget
|
|
39
|
+
fetch(`/admin/questions/update_nested_form?type=${questionType}&kind=${questionKind}`, {
|
|
40
|
+
method: 'GET',
|
|
41
|
+
}).then(response => response.json())
|
|
42
|
+
.then(data => {
|
|
43
|
+
choices.innerHTML = data
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
displayChoiceBtn() {
|
|
48
|
+
let questionKind = this.questionKindTarget.selectedOptions[0].value
|
|
49
|
+
let questionType = this.questionTypeTarget.selectedOptions[0].value
|
|
50
|
+
let btn = document.getElementById('add-choice')
|
|
51
|
+
if (Boolean(questionKind) && Boolean(questionType) && questionType != "Questions::Input") {
|
|
52
|
+
btn.classList.remove('hidden')
|
|
53
|
+
} else {
|
|
54
|
+
btn.classList.add('hidden')
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
addQuestion() {
|
|
59
|
+
this.newQuestionTargets[0].classList.remove('hidden')
|
|
60
|
+
location.hash = "#" + 'newQuestion';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["form"]
|
|
5
|
+
|
|
6
|
+
search() {
|
|
7
|
+
const exportBtn = document.getElementById("exportBtn")
|
|
8
|
+
let originalHref = exportBtn.getAttribute("href")
|
|
9
|
+
if (exportBtn) {
|
|
10
|
+
originalHref = originalHref.split('?')[0]
|
|
11
|
+
|
|
12
|
+
const params = this.getQueryParams()
|
|
13
|
+
exportBtn.setAttribute("href", `${originalHref}?${params}`)
|
|
14
|
+
}
|
|
15
|
+
clearTimeout(this.timeout)
|
|
16
|
+
this.timeout = setTimeout(() => {
|
|
17
|
+
this.formTarget.requestSubmit()
|
|
18
|
+
}, 200)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getQueryParams() {
|
|
22
|
+
const formData = new FormData(this.formTarget)
|
|
23
|
+
const params = new URLSearchParams(formData).toString()
|
|
24
|
+
return params
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setBooleanField(e) {
|
|
28
|
+
let value = e.target.getAttribute('data-value')
|
|
29
|
+
let targetId = e.target.getAttribute('data-target-id')
|
|
30
|
+
let target = document.getElementById(targetId)
|
|
31
|
+
target.value = value
|
|
32
|
+
this.formTarget.requestSubmit()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
export default class extends Controller {
|
|
4
|
+
static targets = ["sidebar", "bg"]
|
|
5
|
+
|
|
6
|
+
toggle() {
|
|
7
|
+
this.sidebarTarget.classList.toggle("-translate-x-full")
|
|
8
|
+
this.bgTarget.classList.toggle("opacity-100")
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
close() {
|
|
12
|
+
this.sidebarTarget.classList.add("-translate-x-full")
|
|
13
|
+
this.bgTarget.classList.remove("opacity-100")
|
|
14
|
+
this.bgTarget.classList.add("opacity-0")
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
import { get } from '@rails/request.js'
|
|
3
|
+
import TomSelect from "tom-select"
|
|
4
|
+
|
|
5
|
+
export default class extends Controller {
|
|
6
|
+
static values = { url: String }
|
|
7
|
+
|
|
8
|
+
connect() {
|
|
9
|
+
new TomSelect(this.element, {
|
|
10
|
+
plugins: ['clear_button'],
|
|
11
|
+
valueField: 'value',
|
|
12
|
+
load: (q, callback) => this.search(q, callback)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async search(q, callback) {
|
|
17
|
+
const response = await get(this.urlValue, {
|
|
18
|
+
query: { q: q },
|
|
19
|
+
responseKind: 'json'
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
if (response.ok) {
|
|
23
|
+
const list = await response.json
|
|
24
|
+
callback(list)
|
|
25
|
+
} else {
|
|
26
|
+
callback()
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
19
|
<div class="flex-shrink-0 pr-2">
|
|
20
|
-
<%= button_tag type: :button, data: { controller: "attachments",
|
|
20
|
+
<%= button_tag type: :button, data: { controller: "tybo--attachments", tybo__attachments_method_value: 'delete', tybo__attachments_url_value: @url, tybo__attachments_attachment_id_value: @attachment.id, action: "click->tybo--attachments#toggle" } do %>
|
|
21
21
|
<span class="sr-only">Delete</span>
|
|
22
22
|
<%= render(Icons::TrashComponent.new) %>
|
|
23
23
|
<% end %>
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
</label>
|
|
6
6
|
</div>
|
|
7
7
|
<div class="mt-1 sm:col-span-3 sm:mt-0">
|
|
8
|
-
<%= @form.date_field @from_field, data: { action: "input->search-form#search" }, class: "rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:text-sm" %>
|
|
8
|
+
<%= @form.date_field @from_field, data: { action: "input->tybo--search-form#search" }, class: "rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:text-sm" %>
|
|
9
9
|
</div>
|
|
10
10
|
<div class="mt-1 sm:col-span-2 text-center">
|
|
11
11
|
<%= I18n.t('bo.to') %>
|
|
12
12
|
</div>
|
|
13
13
|
<div class="mt-1 sm:col-span-3 sm:mt-0">
|
|
14
|
-
<%= @form.date_field @to_field, data: { action: "input->search-form#search" }, class: "rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:text-sm" %>
|
|
14
|
+
<%= @form.date_field @to_field, data: { action: "input->tybo--search-form#search" }, class: "rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:text-sm" %>
|
|
15
15
|
</div>
|
|
16
16
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<div data-controller="sidebar">
|
|
1
|
+
<div data-controller="tybo--sidebar">
|
|
2
2
|
<!-- Barre de navigation mobile avec bouton d'ouverture du menu -->
|
|
3
3
|
<div class="sticky top-0 z-40 flex items-center h-16 px-4 border-b border-gray-200 shadow-sm bg-tybo lg:hidden shrink-0 gap-x-4 sm:gap-x-6 sm:px-6 lg:px-8">
|
|
4
|
-
<button type="button" class="-m-2.5 p-2.5 text-white lg:hidden" data-action="click->sidebar#toggle">
|
|
4
|
+
<button type="button" class="-m-2.5 p-2.5 text-white lg:hidden" data-action="click->tybo--sidebar#toggle">
|
|
5
5
|
<span class="sr-only">Open sidebar</span>
|
|
6
6
|
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
|
|
7
7
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
</button>
|
|
10
10
|
</div>
|
|
11
11
|
<!-- Sidebar mobile avec bouton de fermeture -->
|
|
12
|
-
<div class="fixed inset-0 z-50 transition-transform duration-300 ease-in-out transform -translate-x-full" data-sidebar-target="sidebar">
|
|
13
|
-
<div class="fixed inset-0 bg-gray-900/80 " aria-hidden="true" data-sidebar-target="bg"></div>
|
|
12
|
+
<div class="fixed inset-0 z-50 transition-transform duration-300 ease-in-out transform -translate-x-full" data-tybo--sidebar-target="sidebar">
|
|
13
|
+
<div class="fixed inset-0 bg-gray-900/80 " aria-hidden="true" data-tybo--sidebar-target="bg"></div>
|
|
14
14
|
<div class="fixed inset-0 flex">
|
|
15
15
|
<div class="relative flex flex-1 w-full max-w-xs mr-16">
|
|
16
16
|
<div class="absolute top-0 flex justify-center w-16 pt-5 left-full">
|
|
17
|
-
<button type="button" class="-m-2.5 p-2.5" data-action="click->sidebar#close">
|
|
17
|
+
<button type="button" class="-m-2.5 p-2.5" data-action="click->tybo--sidebar#close">
|
|
18
18
|
<span class="sr-only">Close sidebar</span>
|
|
19
19
|
<svg class="w-6 h-6 text-white" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" aria-hidden="true">
|
|
20
20
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<div class="rounded-md bg-red-alert text-white p-4 my-3" data-controller="flash">
|
|
1
|
+
<div class="rounded-md bg-red-alert text-white p-4 my-3" data-controller="tybo--flash">
|
|
2
2
|
<div class="flex">
|
|
3
3
|
<div class="flex-shrink-0">
|
|
4
4
|
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
<div class="ml-auto pl-3">
|
|
12
12
|
<div class="-mx-1.5 -my-1.5">
|
|
13
|
-
<button type="button" data-action="flash#dismiss" class="inline-flex bg-red-50 rounded-md p-1.5 text-red-alert hover:bg-red-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-red-50 focus:ring-red-600">
|
|
13
|
+
<button type="button" data-action="tybo--flash#dismiss" class="inline-flex bg-red-50 rounded-md p-1.5 text-red-alert hover:bg-red-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-red-50 focus:ring-red-600">
|
|
14
14
|
<span class="sr-only">Dismiss</span>
|
|
15
15
|
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
16
16
|
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<% flash.each do |key, errors| %>
|
|
2
|
-
<div class="rounded-md <%= classes_for_flash(key) %> p-4 m-4" data-controller="flash">
|
|
2
|
+
<div class="rounded-md <%= classes_for_flash(key) %> p-4 m-4" data-controller="tybo--flash">
|
|
3
3
|
<div class="flex">
|
|
4
4
|
<div class="flex-shrink-0">
|
|
5
5
|
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</div>
|
|
12
12
|
<div class="ml-auto pl-3">
|
|
13
13
|
<div class="-mx-1.5 -my-1.5">
|
|
14
|
-
<button type="button" data-action="flash#dismiss" class="inline-flex rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2">
|
|
14
|
+
<button type="button" data-action="tybo--flash#dismiss" class="inline-flex rounded-md p-1.5 focus:outline-none focus:ring-2 focus:ring-offset-2">
|
|
15
15
|
<span class="sr-only"><%= I18n.t('bo.flash.close')%></span>
|
|
16
16
|
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
17
17
|
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"/>
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
|
|
2
|
+
<html class="h-full bg-white">
|
|
3
3
|
<head>
|
|
4
4
|
<title>TY-BO</title>
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
6
|
<%= csrf_meta_tags %>
|
|
7
7
|
<%= csp_meta_tag %>
|
|
8
|
-
<%=
|
|
8
|
+
<%= stylesheet_link_tag "tybo_admin", "data-turbo-track": "reload" %>
|
|
9
|
+
<%= javascript_importmap_tags "application_tybo_admin" %>
|
|
9
10
|
</head>
|
|
10
11
|
<body class="h-full">
|
|
11
12
|
<main class="flex min-h-full">
|
data/config/importmap.rb
ADDED
|
File without changes
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
<%= association.klass.name %>.all.map { |item| [item.<%=bo_model_title(association.klass.name.constantize)%>, item.id] },
|
|
45
45
|
{ include_blank: true },
|
|
46
46
|
multiple: true,
|
|
47
|
-
data: { controller: 'ts--select' } %>
|
|
47
|
+
data: { controller: 'tybo--ts--select' } %>
|
|
48
48
|
<%% end %>
|
|
49
49
|
<%- end -%>
|
|
50
50
|
<%%= render(Forms::SubmitButtonComponent.new) %>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<div class="relative inline-block mt-3 text-left" data-controller="dropdown">
|
|
1
|
+
<div class="relative inline-block mt-3 text-left" data-controller="tybo--dropdown">
|
|
2
2
|
<div>
|
|
3
|
-
<button data-action="click->dropdown#toggle click@window->dropdown#hide" type="button" class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none " id="menu-button" aria-expanded="true" aria-haspopup="true">
|
|
3
|
+
<button data-action="click->tybo--dropdown#toggle click@window->tybo--dropdown#hide" type="button" class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none " id="menu-button" aria-expanded="true" aria-haspopup="true">
|
|
4
4
|
<%%= I18n.t('bo.filters') %>
|
|
5
5
|
<svg class="w-5 h-5 ml-2 -mr-1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
6
6
|
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd" />
|
|
7
7
|
</svg>
|
|
8
8
|
</button>
|
|
9
9
|
</div>
|
|
10
|
-
<div data-dropdown-target="menu" class="drop-shadow-md hidden absolute py-5 px-5 left-0 z-10 mt-2 w-[40rem] origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
|
11
|
-
<%%= search_form_for [:<%=options[:namespace].underscore %>, @q], method: :post, class: "", data: { controller: "search-form",
|
|
10
|
+
<div data-tybo--dropdown-target="menu" class="drop-shadow-md hidden absolute py-5 px-5 left-0 z-10 mt-2 w-[40rem] origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
|
11
|
+
<%%= search_form_for [:<%=options[:namespace].underscore %>, @q], method: :post, class: "", data: { controller: "tybo--search-form", "tybo--search-form-target": "form", turbo_frame: '<%=class_name.underscore.pluralize%>' } do |f| %>
|
|
12
12
|
<!-- columns -->
|
|
13
13
|
<%- bo_model.columns.group_by(&:type).each do |type| -%>
|
|
14
14
|
<%- type.second.sort_by(&:type).each do |col| -%>
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
<%- next if bo_model.reflect_on_all_associations.map(&:foreign_key).include?(col.name) -%>
|
|
17
17
|
<%- if col.type == :string || col.type == :text -%>
|
|
18
18
|
<%%= render(Forms::SearchInputComponent.new(label: I18n.t('bo.<%= class_name.underscore %>.attributes.<%= col.name %>'))) do %>
|
|
19
|
-
<%%= f.text_field :<%= col.name %>_cont, placeholder: I18n.t('bo.<%= class_name.underscore %>.attributes.<%= col.name %>'), data: { action: "input->search-form#search" }, class: "block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:max-w-xs sm:text-sm" %>
|
|
19
|
+
<%%= f.text_field :<%= col.name %>_cont, placeholder: I18n.t('bo.<%= class_name.underscore %>.attributes.<%= col.name %>'), data: { action: "input->tybo--search-form#search" }, class: "block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:max-w-xs sm:text-sm" %>
|
|
20
20
|
<%% end %>
|
|
21
21
|
<%- elsif col.type ==:integer -%>
|
|
22
22
|
<%%= render(Forms::SearchInputComponent.new(label: I18n.t('bo.<%= class_name.underscore %>.attributes.<%= col.name %>'))) do %>
|
|
23
|
-
<%%= f.number_field :<%= col.name %>_eq, placeholder: I18n.t('bo.<%= class_name.underscore %>.attributes.<%= col.name %>'), data: { action: "input->search-form#search" }, class: "block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:max-w-xs sm:text-sm" %>
|
|
23
|
+
<%%= f.number_field :<%= col.name %>_eq, placeholder: I18n.t('bo.<%= class_name.underscore %>.attributes.<%= col.name %>'), data: { action: "input->tybo--search-form#search" }, class: "block w-full max-w-lg rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:max-w-xs sm:text-sm" %>
|
|
24
24
|
<%% end %>
|
|
25
25
|
<%- elsif col.type == :boolean -%>
|
|
26
26
|
<div class="pt-5 sm:grid sm:grid-cols-3 sm:items-start sm:gap-4">
|
|
@@ -31,23 +31,23 @@
|
|
|
31
31
|
<span class="inline-flex rounded-md shadow-sm isolate">
|
|
32
32
|
<button type="button"
|
|
33
33
|
data-target-id='q_<%= col.name %>_eq'
|
|
34
|
-
data-action="click->search-form#setBooleanField"
|
|
34
|
+
data-action="click->tybo--search-form#setBooleanField"
|
|
35
35
|
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-l-md hover:bg-gray-50 focus:z-10 focus:border-tybo-500 focus:outline-none focus:ring-1 focus:ring-tybo-500">
|
|
36
36
|
-
|
|
37
37
|
</button>
|
|
38
38
|
<button type="button"
|
|
39
|
-
data-action="click->search-form#setBooleanField"
|
|
39
|
+
data-action="click->tybo--search-form#setBooleanField"
|
|
40
40
|
data-value='true'
|
|
41
41
|
data-target-id='q_<%= col.name %>_eq'
|
|
42
42
|
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-l-md hover:bg-gray-50 focus:z-10 focus:border-tybo-500 focus:outline-none focus:ring-1 focus:ring-tybo-500">ON
|
|
43
43
|
</button>
|
|
44
44
|
<button type="button"
|
|
45
|
-
data-action="click->search-form#setBooleanField"
|
|
45
|
+
data-action="click->tybo--search-form#setBooleanField"
|
|
46
46
|
data-value='false'
|
|
47
47
|
data-target-id='q_<%= col.name %>_eq'
|
|
48
48
|
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-l-md hover:bg-gray-50 focus:z-10 focus:border-tybo-500 focus:outline-none focus:ring-1 focus:ring-tybo-500">OFF</button>
|
|
49
49
|
</span>
|
|
50
|
-
<%%= f.hidden_field :<%= col.name %>_eq, value: nil, data: { action: "change->search-form#search"}%>
|
|
50
|
+
<%%= f.hidden_field :<%= col.name %>_eq, value: nil, data: { action: "change->tybo--search-form#search"}%>
|
|
51
51
|
</div>
|
|
52
52
|
</div>
|
|
53
53
|
<%- elsif col.type == :datetime || col.type == :date -%>
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<%%= I18n.t('bo.<%=association.klass.name.underscore%>.one') %>
|
|
67
67
|
</label>
|
|
68
68
|
<div class="mt-1 sm:col-span-2 sm:mt-0">
|
|
69
|
-
<%%= f.select :<%= association.foreign_key %>_eq, <%=association.klass.name.constantize%>.all.map { |value| [value.<%=bo_model_title(association.class_name.constantize)%>, value.id] }, { include_blank: true }, { class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:text-sm", data: { action: "input->search-form#search" } } %>
|
|
69
|
+
<%%= f.select :<%= association.foreign_key %>_eq, <%=association.klass.name.constantize%>.all.map { |value| [value.<%=bo_model_title(association.class_name.constantize)%>, value.id] }, { include_blank: true }, { class: "block w-full rounded-md border-gray-300 shadow-sm focus:border-tybo-500 focus:ring-tybo-500 sm:text-sm", data: { action: "input->tybo--search-form#search" } } %>
|
|
70
70
|
</div>
|
|
71
71
|
</div>
|
|
72
72
|
<%- end -%>
|
|
@@ -6,7 +6,7 @@ class BoNamespaceGenerator < Rails::Generators::NamedBase
|
|
|
6
6
|
|
|
7
7
|
def create_bo_namespace_files
|
|
8
8
|
run "bundle exec rails g devise #{file_name.capitalize}"
|
|
9
|
-
|
|
9
|
+
rails_command "db:migrate"
|
|
10
10
|
create_routes_and_views
|
|
11
11
|
template 'admin.html.erb', File.join('app/views/layouts/', "#{singular_name}.html.erb")
|
|
12
12
|
template 'admin_controller.rb', File.join('app/controllers/', "#{singular_name}_controller.rb")
|
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
6
|
<%%= csrf_meta_tags %>
|
|
7
7
|
<%%= csp_meta_tag %>
|
|
8
|
-
<%%= stylesheet_link_tag "
|
|
9
|
-
<%%=
|
|
10
|
-
<%%= javascript_importmap_tags %>
|
|
11
|
-
<%%= hotwire_livereload_tags if Rails.env.development? %>
|
|
8
|
+
<%%= stylesheet_link_tag "tybo_admin", "data-turbo-track": "reload" %>
|
|
9
|
+
<%%= javascript_importmap_tags "application_tybo_admin" %>
|
|
12
10
|
</head>
|
|
13
11
|
<body class="h-full bg-home">
|
|
14
12
|
<%% if <%= class_name.underscore %>_signed_in? %>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "@hotwired/turbo-rails"
|
|
2
|
+
import { Application } from "@hotwired/stimulus"
|
|
3
|
+
|
|
4
|
+
import Attachments from "tybo/controllers/attachments_controller"
|
|
5
|
+
import Dropdown from "tybo/controllers/dropdown_controller"
|
|
6
|
+
import Flash from "tybo/controllers/flash_controller"
|
|
7
|
+
import SearchForm from "tybo/controllers/search_form_controller"
|
|
8
|
+
import TsSearch from "tybo/controllers/ts/search_controller"
|
|
9
|
+
import TsSelect from "tybo/controllers/ts/select_controller"
|
|
10
|
+
import Sidebar from "tybo/controllers/sidebar_controller"
|
|
11
|
+
|
|
12
|
+
const application = Application.start()
|
|
13
|
+
|
|
14
|
+
application.register("tybo--attachments", Attachments)
|
|
15
|
+
application.register("tybo--dropdown", Dropdown)
|
|
16
|
+
application.register("tybo--flash", Flash)
|
|
17
|
+
application.register("tybo--search-form", SearchForm)
|
|
18
|
+
application.register("tybo--ts--search", TsSearch)
|
|
19
|
+
application.register("tybo--ts--select", TsSelect)
|
|
20
|
+
application.register("tybo--sidebar", Sidebar)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
@import 'actiontext.css';
|
|
5
|
+
|
|
6
|
+
/* pagination */
|
|
7
|
+
.pagy-nav,
|
|
8
|
+
.pagy-nav-js {
|
|
9
|
+
@apply flex space-x-2;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.pagy-nav .page a,
|
|
13
|
+
.pagy-nav .page.active,
|
|
14
|
+
.pagy-nav .page.prev.disabled,
|
|
15
|
+
.pagy-nav .page.next.disabled,
|
|
16
|
+
.pagy-nav-js .page a,
|
|
17
|
+
.pagy-nav-js .page.active,
|
|
18
|
+
.pagy-nav-js .page.prev.disabled,
|
|
19
|
+
.pagy-nav-js .page.next.disabled {
|
|
20
|
+
@apply block rounded-lg px-3 py-1 text-sm text-tybo-500 font-semibold bg-tybo-200 shadow-md;
|
|
21
|
+
|
|
22
|
+
&:hover {
|
|
23
|
+
@apply bg-tybo-300;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&:active {
|
|
27
|
+
@apply bg-tybo-400 text-white;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.pagy-nav .page.prev.disabled,
|
|
32
|
+
.pagy-nav .page.next.disabled,
|
|
33
|
+
.pagy-nav-js .page.prev.disabled,
|
|
34
|
+
.pagy-nav-js .page.next.disabled {
|
|
35
|
+
@apply text-tybo-400 cursor-default;
|
|
36
|
+
|
|
37
|
+
&:hover {
|
|
38
|
+
@apply text-tybo-400 bg-tybo-200;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&:active {
|
|
42
|
+
@apply text-tybo-400 bg-tybo-200;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.pagy-nav .page.active,
|
|
47
|
+
.pagy-nav-js .page.active {
|
|
48
|
+
@apply text-white cursor-default bg-tybo-400;
|
|
49
|
+
|
|
50
|
+
&:hover {
|
|
51
|
+
@apply text-white bg-tybo-400;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&:active {
|
|
55
|
+
@apply bg-tybo-400 text-white;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
.pagy-combo-nav-js {
|
|
61
|
+
@apply flex max-w-max rounded-full px-3 py-1 text-sm text-tybo-500 font-semibold bg-tybo-200 shadow-md;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.pagy-combo-nav-js .pagy-combo-input {
|
|
65
|
+
@apply bg-white px-2 rounded-sm
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.pagy-combo-nav-js .page.prev,
|
|
69
|
+
.pagy-combo-nav-js .page.next {
|
|
70
|
+
&:hover {
|
|
71
|
+
@apply text-tybo-800;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&:active {
|
|
75
|
+
@apply text-tybo-800;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.pagy-combo-nav-js .page.prev.disabled,
|
|
80
|
+
.pagy-combo-nav-js .page.next.disabled {
|
|
81
|
+
@apply text-tybo-400 cursor-default;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* tom-select */
|
|
85
|
+
ts-wrapper {
|
|
86
|
+
@apply w-full !ml-0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ts-control {
|
|
90
|
+
@apply shadow-sm rounded-lg my-5 border-tybo-300 bg-white py-2 px-3 text-base;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.ts-dropdown {
|
|
94
|
+
@apply rounded-md border border-solid border-t border-tybo-300 text-base;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.ts-dropdown [data-selectable].option:first-child {
|
|
98
|
+
@apply rounded-t-lg;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.ts-dropdown [data-selectable].option:last-child {
|
|
102
|
+
@apply rounded-b-lg;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.ts-dropdown .create:hover,
|
|
106
|
+
.ts-dropdown .option:hover {
|
|
107
|
+
@apply bg-sky-50 text-sky-900;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.ts-dropdown .active {
|
|
111
|
+
@apply bg-tybo-100 text-tybo-900;
|
|
112
|
+
}
|
|
@@ -4,6 +4,6 @@ Tybo.configure do |config|
|
|
|
4
4
|
# customise logo and cover url
|
|
5
5
|
# should be an external url or image should be present in (app/assets/images)
|
|
6
6
|
config.logo_url = 'logo.svg'
|
|
7
|
-
config.nav_logo_url = '
|
|
7
|
+
config.nav_logo_url = 'logo.svg'
|
|
8
8
|
config.cover_url = 'cover.svg'
|
|
9
9
|
end
|
|
@@ -11,12 +11,11 @@ class TyboInstallGenerator < Rails::Generators::Base
|
|
|
11
11
|
gem 'simple_form-tailwind', '~> 0.1.1' unless Bundler.locked_gems.specs.any? { |gem| gem.name == 'simple_form-tailwind' }
|
|
12
12
|
gem 'action_policy', '~> 0.7.5' unless Bundler.locked_gems.specs.any? { |gem| gem.name == 'actionpolicy' }
|
|
13
13
|
run 'bundle install'
|
|
14
|
-
run "rails tailwindcss:install"
|
|
15
14
|
end
|
|
16
15
|
|
|
17
16
|
def create_configuration_files
|
|
18
17
|
create_base_translation_files
|
|
19
|
-
template '
|
|
18
|
+
template 'tybo_admin.tailwind.css', File.join('app/assets/stylesheets/tybo_admin.tailwind.css')
|
|
20
19
|
template 'tailwind.config.js', File.join('config/tailwind.config.js'), force: true
|
|
21
20
|
template 'tom-select.css', File.join('app/assets/stylesheets/tom-select.css')
|
|
22
21
|
template 'simple_form_tailwind.rb', File.join('config/initializers/simple_form_tailwind.rb')
|
|
@@ -24,8 +23,23 @@ class TyboInstallGenerator < Rails::Generators::Base
|
|
|
24
23
|
end
|
|
25
24
|
|
|
26
25
|
def pin_js_dependencies
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
inject_into_file 'config/importmap.rb', before: /\z/ do
|
|
27
|
+
<<~RUBY
|
|
28
|
+
|
|
29
|
+
pin "tom-select", to: "https://esm.sh/tom-select"
|
|
30
|
+
pin "@rails/request.js", to: "https://esm.sh/@rails/request.js"
|
|
31
|
+
RUBY
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def setup_puma_plugin
|
|
36
|
+
inject_into_file 'config/puma.rb', before: /\z/ do
|
|
37
|
+
"\nplugin :tybo if ENV.fetch(\"RAILS_ENV\", \"development\") == \"development\"\n"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build_css
|
|
42
|
+
rake "tybo:build_css"
|
|
29
43
|
end
|
|
30
44
|
|
|
31
45
|
def create_routes
|
|
@@ -37,13 +51,19 @@ class TyboInstallGenerator < Rails::Generators::Base
|
|
|
37
51
|
run 'rails g bo_namespace Administrator'
|
|
38
52
|
end
|
|
39
53
|
|
|
54
|
+
def copy_javascript_controllers
|
|
55
|
+
js_source = Tybo::Engine.root.join("app/assets/javascripts/tybo/controllers")
|
|
56
|
+
js_dest = "app/javascript/tybo/controllers"
|
|
57
|
+
|
|
58
|
+
directory js_source.to_s, js_dest
|
|
59
|
+
end
|
|
60
|
+
|
|
40
61
|
def add_javascript_controllers
|
|
41
|
-
|
|
42
|
-
"import { Dropdown, Flash, SearchForm, TsSearch, TsSelect, Sidebar } from \"@tymate/tybo_js\"\n"
|
|
43
|
-
end
|
|
62
|
+
template 'application_tybo_admin.js', 'app/javascript/tybo/application_tybo_admin.js'
|
|
44
63
|
|
|
45
|
-
inject_into_file '
|
|
46
|
-
"
|
|
64
|
+
inject_into_file 'config/importmap.rb', before: /\z/ do
|
|
65
|
+
"\npin \"application_tybo_admin\", to: \"tybo/application_tybo_admin.js\"\n" \
|
|
66
|
+
"pin_all_from \"app/javascript/tybo/controllers\", under: \"tybo/controllers\"\n"
|
|
47
67
|
end
|
|
48
68
|
end
|
|
49
69
|
|
|
@@ -1,15 +1,48 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
FR_DATE_TRANSLATIONS = {
|
|
4
|
+
'date' => {
|
|
5
|
+
'abbr_day_names' => %w[Dim Lun Mar Mer Jeu Ven Sam],
|
|
6
|
+
'day_names' => %w[Dimanche Lundi Mardi Mercredi Jeudi Vendredi Samedi],
|
|
7
|
+
'abbr_month_names' => [nil, 'Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc'],
|
|
8
|
+
'month_names' => [nil, 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
|
|
9
|
+
'formats' => { 'default' => '%d/%m/%Y', 'short' => '%e %b', 'long' => '%e %B %Y' }
|
|
10
|
+
},
|
|
11
|
+
'time' => {
|
|
12
|
+
'am' => 'am',
|
|
13
|
+
'pm' => 'pm',
|
|
14
|
+
'formats' => { 'default' => '%A %d %B %Y %H:%M:%S %z', 'short' => '%d %b %H:%M', 'long' => '%A %d %B %Y %H:%M' }
|
|
15
|
+
},
|
|
16
|
+
'datetime' => {
|
|
17
|
+
'distance_in_words' => {
|
|
18
|
+
'half_a_minute' => 'une demi-minute',
|
|
19
|
+
'less_than_x_seconds' => { 'one' => "moins d'une seconde", 'other' => 'moins de %{count} secondes' },
|
|
20
|
+
'x_seconds' => { 'one' => '1 seconde', 'other' => '%{count} secondes' },
|
|
21
|
+
'less_than_x_minutes' => { 'one' => "moins d'une minute", 'other' => 'moins de %{count} minutes' },
|
|
22
|
+
'x_minutes' => { 'one' => '1 minute', 'other' => '%{count} minutes' },
|
|
23
|
+
'about_x_hours' => { 'one' => 'environ 1 heure', 'other' => 'environ %{count} heures' },
|
|
24
|
+
'x_days' => { 'one' => '1 jour', 'other' => '%{count} jours' },
|
|
25
|
+
'about_x_months' => { 'one' => 'environ 1 mois', 'other' => 'environ %{count} mois' },
|
|
26
|
+
'x_months' => { 'one' => '1 mois', 'other' => '%{count} mois' },
|
|
27
|
+
'about_x_years' => { 'one' => 'environ 1 an', 'other' => 'environ %{count} ans' },
|
|
28
|
+
'over_x_years' => { 'one' => "plus d'un an", 'other' => 'plus de %{count} ans' },
|
|
29
|
+
'almost_x_years' => { 'one' => 'presque 1 an', 'other' => 'presque %{count} ans' }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
3
34
|
def create_base_translation_files
|
|
4
35
|
%w[en fr].each do |locale|
|
|
5
36
|
locale_file = "config/locales/bo.#{locale}.yml"
|
|
37
|
+
extra = locale == 'fr' ? FR_DATE_TRANSLATIONS : {}
|
|
6
38
|
File.write(locale_file, {
|
|
7
|
-
locale => {
|
|
39
|
+
locale => extra.merge({
|
|
8
40
|
'bo' => {
|
|
9
41
|
'filters' => find_existing_translation('filters', locale),
|
|
10
42
|
'show' => find_existing_translation('show', locale),
|
|
11
43
|
'to' => find_existing_translation('to', locale),
|
|
12
44
|
'export_btn' => find_existing_translation('export_btn', locale),
|
|
45
|
+
'add_ressource_btn' => find_existing_translation('add_ressource_btn', locale),
|
|
13
46
|
'confirm_delete' => find_existing_translation('confirm_delete', locale),
|
|
14
47
|
'record' => {
|
|
15
48
|
'created' => find_existing_translation('created', locale),
|
|
@@ -38,7 +71,7 @@
|
|
|
38
71
|
'save' => find_existing_translation('save', locale),
|
|
39
72
|
}
|
|
40
73
|
}
|
|
41
|
-
}
|
|
74
|
+
})
|
|
42
75
|
}.to_yaml)
|
|
43
76
|
end
|
|
44
77
|
end
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class TyboUpgradeGenerator < Rails::Generators::Base
|
|
4
|
+
# Reuse the install templates (application_tybo_admin.js, tybo_admin.tailwind.css)
|
|
5
|
+
source_root File.expand_path("../tybo_install/templates", __dir__)
|
|
6
|
+
|
|
7
|
+
TYBO_CONTROLLERS = %w[
|
|
8
|
+
attachments_controller
|
|
9
|
+
dropdown_controller
|
|
10
|
+
flash_controller
|
|
11
|
+
search_form_controller
|
|
12
|
+
sidebar_controller
|
|
13
|
+
ts/search_controller
|
|
14
|
+
ts/select_controller
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
def upgrade_css
|
|
18
|
+
say_status :upgrade, "CSS → tybo_admin.css", :blue
|
|
19
|
+
|
|
20
|
+
unless File.exist?("app/assets/stylesheets/tybo_admin.tailwind.css")
|
|
21
|
+
if File.exist?("app/assets/stylesheets/application.tailwind.css")
|
|
22
|
+
FileUtils.cp("app/assets/stylesheets/application.tailwind.css",
|
|
23
|
+
"app/assets/stylesheets/tybo_admin.tailwind.css")
|
|
24
|
+
say_status :info, "Copied application.tailwind.css → tybo_admin.tailwind.css", :green
|
|
25
|
+
else
|
|
26
|
+
template "tybo_admin.tailwind.css", "app/assets/stylesheets/tybo_admin.tailwind.css"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
unless File.read("config/puma.rb").include?("plugin :tybo")
|
|
31
|
+
inject_into_file "config/puma.rb", before: /\z/ do
|
|
32
|
+
"\nplugin :tybo if ENV.fetch(\"RAILS_ENV\", \"development\") == \"development\"\n"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def upgrade_layouts
|
|
38
|
+
say_status :upgrade, "Admin layouts", :blue
|
|
39
|
+
|
|
40
|
+
Dir.glob("app/views/layouts/*.html.erb").each do |layout|
|
|
41
|
+
content = File.read(layout)
|
|
42
|
+
next unless content.include?("tailwind") || content.include?("@tymate")
|
|
43
|
+
|
|
44
|
+
# stylesheet : retire "application" + remplace "tailwind"
|
|
45
|
+
gsub_file layout,
|
|
46
|
+
/[ \t]*<%=[ \t]*stylesheet_link_tag[ \t]+"application"[^%]*%>\n/, ""
|
|
47
|
+
gsub_file layout,
|
|
48
|
+
/stylesheet_link_tag "tailwind"[^%]*%>/,
|
|
49
|
+
'stylesheet_link_tag "tybo_admin", "data-turbo-track": "reload" %>'
|
|
50
|
+
gsub_file layout,
|
|
51
|
+
/, "inter-font"/, ""
|
|
52
|
+
|
|
53
|
+
# importmap
|
|
54
|
+
gsub_file layout,
|
|
55
|
+
/javascript_importmap_tags(?!\s+"application_tybo_admin")/,
|
|
56
|
+
'javascript_importmap_tags "application_tybo_admin"'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def upgrade_importmap
|
|
61
|
+
say_status :upgrade, "config/importmap.rb", :blue
|
|
62
|
+
|
|
63
|
+
# Remove old pins
|
|
64
|
+
gsub_file "config/importmap.rb",
|
|
65
|
+
/.*pin "@tymate\/tybo_js".*\n/, ""
|
|
66
|
+
gsub_file "config/importmap.rb",
|
|
67
|
+
/.*pin "tom-select".*\n/, ""
|
|
68
|
+
gsub_file "config/importmap.rb",
|
|
69
|
+
/.*pin "@rails\/request\.js".*\n/, ""
|
|
70
|
+
gsub_file "config/importmap.rb",
|
|
71
|
+
/.*pin_all_from "app\/javascript\/tybo\/controllers".*\n/, ""
|
|
72
|
+
gsub_file "config/importmap.rb",
|
|
73
|
+
/.*pin "application_tybo_admin".*\n/, ""
|
|
74
|
+
|
|
75
|
+
inject_into_file "config/importmap.rb", before: /\z/ do
|
|
76
|
+
<<~RUBY
|
|
77
|
+
|
|
78
|
+
pin "application_tybo_admin", to: "tybo/application_tybo_admin.js"
|
|
79
|
+
pin_all_from "app/javascript/tybo/controllers", under: "tybo/controllers"
|
|
80
|
+
pin "tom-select", to: "https://esm.sh/tom-select"
|
|
81
|
+
pin "@rails/request.js", to: "https://esm.sh/@rails/request.js"
|
|
82
|
+
RUBY
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def upgrade_javascript
|
|
87
|
+
say_status :upgrade, "JavaScript entry point", :blue
|
|
88
|
+
|
|
89
|
+
# Copy JS controllers from engine into the host app
|
|
90
|
+
js_source = Tybo::Engine.root.join("app/assets/javascripts/tybo/controllers")
|
|
91
|
+
js_dest = "app/javascript/tybo/controllers"
|
|
92
|
+
directory js_source.to_s, js_dest, force: false
|
|
93
|
+
say_status :info, "Copied Tybo controllers to #{js_dest} (existing files kept)", :green
|
|
94
|
+
|
|
95
|
+
# Create application_tybo_admin.js (entry point for admin)
|
|
96
|
+
template "application_tybo_admin.js", "app/javascript/tybo/application_tybo_admin.js"
|
|
97
|
+
|
|
98
|
+
# In index.js, comment out the tybo controller exports that are now
|
|
99
|
+
# handled by application_tybo_admin.js — without deleting anything
|
|
100
|
+
old_index = "app/javascript/tybo/controllers/index.js"
|
|
101
|
+
if File.exist?(old_index)
|
|
102
|
+
content = File.read(old_index, encoding: "UTF-8")
|
|
103
|
+
TYBO_CONTROLLERS.each do |ctrl|
|
|
104
|
+
basename = File.basename(ctrl)
|
|
105
|
+
content = content.gsub(
|
|
106
|
+
/^(export \{ default as \w+ \} from ".*#{Regexp.escape(basename)}.*")/,
|
|
107
|
+
'// [tybo 0.7] registered in application_tybo_admin.js — \1'
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
File.write(old_index, content, encoding: "UTF-8")
|
|
111
|
+
say_status :info, "Commented out tybo exports in index.js", :yellow
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Comment out (not delete) old tybo registrations from application.js
|
|
115
|
+
app_js = "app/javascript/controllers/application.js"
|
|
116
|
+
if File.exist?(app_js)
|
|
117
|
+
content = File.read(app_js, encoding: "UTF-8")
|
|
118
|
+
if content.include?("@tymate/tybo_js")
|
|
119
|
+
content = content.gsub(
|
|
120
|
+
/^(import \{[^}]+\} from "@tymate\/tybo_js")/,
|
|
121
|
+
'// [tybo 0.7] moved to application_tybo_admin.js — \1'
|
|
122
|
+
)
|
|
123
|
+
%w[dropdown flash search-form ts--search ts--select sidebar].each do |name|
|
|
124
|
+
content = content.gsub(
|
|
125
|
+
/^(application\.register\('#{Regexp.escape(name)}'.*)/,
|
|
126
|
+
'// [tybo 0.7] moved to application_tybo_admin.js — \1'
|
|
127
|
+
)
|
|
128
|
+
end
|
|
129
|
+
File.write(app_js, content, encoding: "UTF-8")
|
|
130
|
+
say_status :info, "Commented out @tymate/tybo_js lines in application.js", :yellow
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def upgrade_data_controllers
|
|
136
|
+
say_status :upgrade, "Stimulus data-controller attributes", :blue
|
|
137
|
+
|
|
138
|
+
views = Dir.glob("app/views/**/*.html.erb") + Dir.glob("app/components/**/*.html.erb")
|
|
139
|
+
|
|
140
|
+
views.each do |file|
|
|
141
|
+
content = File.read(file, encoding: "UTF-8")
|
|
142
|
+
|
|
143
|
+
next unless content.match?(/
|
|
144
|
+
data-controller="(sidebar|flash|dropdown|search-form|ts--|attachments)" |
|
|
145
|
+
->sidebar\# | ->flash\# | ->dropdown\# | ->search-form\# |
|
|
146
|
+
->ts--select\# | ->ts--search\# | ->attachments\# |
|
|
147
|
+
data-sidebar-target | data-dropdown-target
|
|
148
|
+
/x)
|
|
149
|
+
|
|
150
|
+
{
|
|
151
|
+
'data-controller="sidebar"' => 'data-controller="tybo--sidebar"',
|
|
152
|
+
'data-controller="flash"' => 'data-controller="tybo--flash"',
|
|
153
|
+
'data-controller="dropdown"' => 'data-controller="tybo--dropdown"',
|
|
154
|
+
'data-controller="search-form"' => 'data-controller="tybo--search-form"',
|
|
155
|
+
'data-controller="ts--select"' => 'data-controller="tybo--ts--select"',
|
|
156
|
+
'data-controller="ts--search"' => 'data-controller="tybo--ts--search"',
|
|
157
|
+
'data-controller="attachments"' => 'data-controller="tybo--attachments"',
|
|
158
|
+
'data-sidebar-target' => 'data-tybo--sidebar-target',
|
|
159
|
+
'data-dropdown-target' => 'data-tybo--dropdown-target',
|
|
160
|
+
'->sidebar#' => '->tybo--sidebar#',
|
|
161
|
+
'->flash#' => '->tybo--flash#',
|
|
162
|
+
'->dropdown#' => '->tybo--dropdown#',
|
|
163
|
+
'->search-form#' => '->tybo--search-form#',
|
|
164
|
+
'->ts--select#' => '->tybo--ts--select#',
|
|
165
|
+
'->ts--search#' => '->tybo--ts--search#',
|
|
166
|
+
'->attachments#' => '->tybo--attachments#',
|
|
167
|
+
'search_form_target:' => '"tybo--search-form-target":',
|
|
168
|
+
"controller: 'ts--select'" => "controller: 'tybo--ts--select'",
|
|
169
|
+
'controller: "search-form"' => 'controller: "tybo--search-form"'
|
|
170
|
+
}.each { |from, to| content = content.gsub(from, to) }
|
|
171
|
+
|
|
172
|
+
File.write(file, content, encoding: "UTF-8")
|
|
173
|
+
say_status :gsub, file, :green
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def build_css
|
|
178
|
+
say_status :upgrade, "Building tybo_admin.css", :blue
|
|
179
|
+
rake "tybo:build_css"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def done
|
|
183
|
+
say ""
|
|
184
|
+
say "✓ Tybo upgraded to 0.7.x", :green
|
|
185
|
+
say ""
|
|
186
|
+
say "Files to review:", :yellow
|
|
187
|
+
say " app/javascript/tybo/controllers/ (controllers copied from engine)", :yellow
|
|
188
|
+
say " app/javascript/tybo/controllers/index.js (exports commented out)", :yellow
|
|
189
|
+
say " app/javascript/controllers/application.js (registrations commented out)", :yellow
|
|
190
|
+
say ""
|
|
191
|
+
say "Once reviewed, you can delete the commented lines safely."
|
|
192
|
+
end
|
|
193
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require "tailwindcss/ruby"
|
|
2
|
+
|
|
3
|
+
Puma::Plugin.create do
|
|
4
|
+
def start(launcher)
|
|
5
|
+
in_background do
|
|
6
|
+
rails_root = defined?(Rails) ? Rails.root : Pathname.new(Dir.pwd)
|
|
7
|
+
|
|
8
|
+
input = rails_root.join("app/assets/stylesheets/tybo_admin.tailwind.css")
|
|
9
|
+
output = rails_root.join("app/assets/builds/tybo_admin.css")
|
|
10
|
+
config = rails_root.join("config/tailwind.config.js")
|
|
11
|
+
|
|
12
|
+
unless input.exist?
|
|
13
|
+
launcher.log_writer.write("Tybo: #{input} not found, skipping CSS watch\n")
|
|
14
|
+
next
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
command = [
|
|
18
|
+
Tailwindcss::Ruby.executable,
|
|
19
|
+
"-i", input.to_s,
|
|
20
|
+
"-o", output.to_s,
|
|
21
|
+
"-c", config.to_s,
|
|
22
|
+
"-w"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
pid = spawn(*command)
|
|
26
|
+
launcher.events.on_stopped { Process.kill(:INT, pid) rescue nil }
|
|
27
|
+
|
|
28
|
+
begin
|
|
29
|
+
Process.wait(pid)
|
|
30
|
+
rescue Interrupt
|
|
31
|
+
Process.kill(:INT, pid) rescue nil
|
|
32
|
+
Process.wait(pid)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/tasks/tybo.rake
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "tailwindcss/ruby"
|
|
2
|
+
|
|
3
|
+
namespace :tybo do
|
|
4
|
+
desc "Build Tybo Admin CSS"
|
|
5
|
+
task build_css: :environment do
|
|
6
|
+
input = Rails.root.join("app/assets/stylesheets/tybo_admin.tailwind.css")
|
|
7
|
+
output = Rails.root.join("app/assets/builds/tybo_admin.css")
|
|
8
|
+
config = Rails.root.join("config/tailwind.config.js")
|
|
9
|
+
|
|
10
|
+
unless input.exist?
|
|
11
|
+
warn "WARNING: #{input} not found, skipping tybo CSS build"
|
|
12
|
+
next
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
command = [
|
|
16
|
+
Tailwindcss::Ruby.executable,
|
|
17
|
+
"-i", input.to_s,
|
|
18
|
+
"-o", output.to_s,
|
|
19
|
+
"-c", config.to_s,
|
|
20
|
+
]
|
|
21
|
+
command << "--minify" unless ENV["TAILWINDCSS_DEBUG"].present?
|
|
22
|
+
|
|
23
|
+
system(*command, exception: true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc "Watch and build Tybo Admin CSS on file changes"
|
|
27
|
+
task watch_css: :environment do
|
|
28
|
+
input = Rails.root.join("app/assets/stylesheets/tybo_admin.tailwind.css")
|
|
29
|
+
output = Rails.root.join("app/assets/builds/tybo_admin.css")
|
|
30
|
+
config = Rails.root.join("config/tailwind.config.js")
|
|
31
|
+
|
|
32
|
+
command = [
|
|
33
|
+
Tailwindcss::Ruby.executable,
|
|
34
|
+
"-i", input.to_s,
|
|
35
|
+
"-o", output.to_s,
|
|
36
|
+
"-c", config.to_s,
|
|
37
|
+
"-w"
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
system(*command)
|
|
41
|
+
rescue Interrupt
|
|
42
|
+
# silent exit on Ctrl-C
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
Rake::Task["assets:precompile"].enhance(["tybo:build_css"])
|
data/lib/tybo/engine.rb
CHANGED
data/lib/tybo/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tybo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michel Delpierre
|
|
@@ -139,8 +139,19 @@ files:
|
|
|
139
139
|
- README.md
|
|
140
140
|
- Rakefile
|
|
141
141
|
- app/assets/config/tybo_manifest.js
|
|
142
|
+
- app/assets/images/cover.svg
|
|
143
|
+
- app/assets/images/logo.svg
|
|
142
144
|
- app/assets/images/tybo/cover.svg
|
|
143
145
|
- app/assets/images/tybo/logo.svg
|
|
146
|
+
- app/assets/javascripts/tybo/controllers/attachments_controller.js
|
|
147
|
+
- app/assets/javascripts/tybo/controllers/dropdown_controller.js
|
|
148
|
+
- app/assets/javascripts/tybo/controllers/flash_controller.js
|
|
149
|
+
- app/assets/javascripts/tybo/controllers/index.js
|
|
150
|
+
- app/assets/javascripts/tybo/controllers/questions_controller.js
|
|
151
|
+
- app/assets/javascripts/tybo/controllers/search_form_controller.js
|
|
152
|
+
- app/assets/javascripts/tybo/controllers/sidebar_controller.js
|
|
153
|
+
- app/assets/javascripts/tybo/controllers/ts/search_controller.js
|
|
154
|
+
- app/assets/javascripts/tybo/controllers/ts/select_controller.js
|
|
144
155
|
- app/assets/stylesheets/tybo/application.css
|
|
145
156
|
- app/components/attachment_card_component.html.erb
|
|
146
157
|
- app/components/attachment_card_component.rb
|
|
@@ -260,6 +271,7 @@ files:
|
|
|
260
271
|
- app/views/layouts/tybo/application.html.erb
|
|
261
272
|
- app/views/login/home.html.erb
|
|
262
273
|
- app/views/shared/_pagination.html.erb
|
|
274
|
+
- config/importmap.rb
|
|
263
275
|
- config/initializers/devise.rb
|
|
264
276
|
- config/initializers/pagy.rb
|
|
265
277
|
- config/initializers/ransack.rb
|
|
@@ -291,14 +303,19 @@ files:
|
|
|
291
303
|
- lib/generators/bo_namespace/utils/files/fr.json
|
|
292
304
|
- lib/generators/bo_namespace/utils/translations.rb
|
|
293
305
|
- lib/generators/tybo_install/templates/application.tailwind.css
|
|
306
|
+
- lib/generators/tybo_install/templates/application_tybo_admin.js
|
|
294
307
|
- lib/generators/tybo_install/templates/simple_form_tailwind.rb
|
|
295
308
|
- lib/generators/tybo_install/templates/tailwind.config.js
|
|
296
309
|
- lib/generators/tybo_install/templates/tom-select.css
|
|
310
|
+
- lib/generators/tybo_install/templates/tybo_admin.tailwind.css
|
|
297
311
|
- lib/generators/tybo_install/templates/tybo_config.rb
|
|
298
312
|
- lib/generators/tybo_install/tybo_install_generator.rb
|
|
299
313
|
- lib/generators/tybo_install/utils/files/en.json
|
|
300
314
|
- lib/generators/tybo_install/utils/files/fr.json
|
|
301
315
|
- lib/generators/tybo_install/utils/translations.rb
|
|
316
|
+
- lib/generators/tybo_upgrade/tybo_upgrade_generator.rb
|
|
317
|
+
- lib/puma/plugin/tybo.rb
|
|
318
|
+
- lib/tasks/tybo.rake
|
|
302
319
|
- lib/tybo.rb
|
|
303
320
|
- lib/tybo/configuration.rb
|
|
304
321
|
- lib/tybo/engine.rb
|