shiplog 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -0
- data/README.md +266 -9
- data/app/controllers/shiplog/admin/area_detections_controller.rb +15 -0
- data/app/controllers/shiplog/admin/area_translations_controller.rb +19 -0
- data/app/controllers/shiplog/admin/areas/merges_controller.rb +19 -0
- data/app/controllers/shiplog/admin/areas/moves_controller.rb +13 -0
- data/app/controllers/shiplog/admin/areas_controller.rb +48 -0
- data/app/controllers/shiplog/admin/entries/images/moves_controller.rb +20 -0
- data/app/controllers/shiplog/admin/entries/images_controller.rb +76 -0
- data/app/controllers/shiplog/admin/entries/translations/retranslations_controller.rb +23 -0
- data/app/controllers/shiplog/admin/entries/translations_controller.rb +35 -0
- data/app/controllers/shiplog/admin/entries_controller.rb +9 -3
- data/app/controllers/shiplog/admin/syncs_controller.rb +3 -2
- data/app/controllers/shiplog/changelog_entries_controller.rb +26 -0
- data/app/controllers/shiplog/changelog_feeds_controller.rb +19 -0
- data/app/controllers/shiplog/changelogs_controller.rb +30 -4
- data/app/controllers/shiplog/public_controller.rb +58 -1
- data/app/controllers/shiplog/roadmaps_controller.rb +27 -2
- data/app/frontend/shiplog/admin.css +9 -0
- data/app/frontend/shiplog/shiplog.css +168 -8
- data/app/helpers/shiplog/admin/entries_helper.rb +15 -0
- data/app/helpers/shiplog/callable_helper.rb +12 -0
- data/app/helpers/shiplog/frontend_helper.rb +1 -0
- data/app/helpers/shiplog/permalink_helper.rb +113 -0
- data/app/helpers/shiplog/roadmap_helper.rb +24 -0
- data/app/helpers/shiplog/switcher_helper.rb +101 -0
- data/app/helpers/shiplog/unseen_helper.rb +9 -0
- data/app/jobs/shiplog/detect_areas_job.rb +18 -0
- data/app/jobs/shiplog/refresh_job.rb +1 -0
- data/app/jobs/shiplog/rewrite_entry_job.rb +4 -1
- data/app/jobs/shiplog/scan_changes_job.rb +19 -5
- data/app/jobs/shiplog/sync_job.rb +1 -1
- data/app/jobs/shiplog/translate_area_job.rb +25 -0
- data/app/jobs/shiplog/translate_entry_job.rb +25 -0
- data/app/models/shiplog/area.rb +156 -0
- data/app/models/shiplog/area_detector.rb +146 -0
- data/app/models/shiplog/area_translator.rb +77 -0
- data/app/models/shiplog/change_candidates.rb +39 -4
- data/app/models/shiplog/entry/images.rb +127 -0
- data/app/models/shiplog/entry.rb +218 -2
- data/app/models/shiplog/entry_translation.rb +15 -0
- data/app/models/shiplog/image_fetcher/downloader.rb +98 -0
- data/app/models/shiplog/image_fetcher/sources.rb +41 -0
- data/app/models/shiplog/image_fetcher.rb +72 -0
- data/app/models/shiplog/image_type.rb +111 -0
- data/app/models/shiplog/pull_request.rb +4 -0
- data/app/models/shiplog/pull_request_upgrade.rb +5 -0
- data/app/models/shiplog/rewriter/prompt.rb +57 -9
- data/app/models/shiplog/rewriter.rb +50 -13
- data/app/models/shiplog/setting.rb +19 -0
- data/app/models/shiplog/sync/pull_request_importer.rb +23 -1
- data/app/models/shiplog/sync/repository_sync.rb +2 -0
- data/app/models/shiplog/sync/upgrade_detector.rb +203 -0
- data/app/models/shiplog/translator/prompt.rb +40 -0
- data/app/models/shiplog/translator.rb +99 -0
- data/app/views/layouts/shiplog/application.html.erb +4 -0
- data/app/views/shiplog/_empty.html.erb +1 -1
- data/app/views/shiplog/_page_header.html.erb +2 -1
- data/app/views/shiplog/_pagination.html.erb +3 -3
- data/app/views/shiplog/_switcher.html.erb +13 -0
- data/app/views/shiplog/admin/_nav.html.erb +2 -1
- data/app/views/shiplog/admin/areas/index.html.erb +78 -0
- data/app/views/shiplog/admin/entries/_entry_row.html.erb +4 -0
- data/app/views/shiplog/admin/entries/_images.html.erb +41 -0
- data/app/views/shiplog/admin/entries/_translations.html.erb +42 -0
- data/app/views/shiplog/admin/entries/edit.html.erb +12 -0
- data/app/views/shiplog/changelog_entries/show.html.erb +25 -0
- data/app/views/shiplog/changelog_feeds/show.atom.builder +24 -0
- data/app/views/shiplog/changelogs/_areas.html.erb +8 -0
- data/app/views/shiplog/changelogs/_entry.html.erb +2 -5
- data/app/views/shiplog/changelogs/_entry_content.html.erb +10 -0
- data/app/views/shiplog/changelogs/_search.html.erb +18 -0
- data/app/views/shiplog/changelogs/show.html.erb +20 -5
- data/app/views/shiplog/roadmaps/_card.html.erb +14 -3
- data/app/views/shiplog/roadmaps/_column.html.erb +4 -4
- data/app/views/shiplog/roadmaps/_shipped.html.erb +15 -0
- data/app/views/shiplog/roadmaps/show.html.erb +11 -2
- data/config/admin_routes.rb +16 -0
- data/config/locales/en.yml +105 -0
- data/config/locales/es.yml +223 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20261027000001_create_shiplog_pull_request_upgrades.rb +30 -0
- data/db/migrate/20261027000002_shiplog_0_3_0.rb +105 -0
- data/lib/generators/shiplog/install/install_generator.rb +29 -1
- data/lib/generators/shiplog/install/templates/initializer.rb.tt +82 -1
- data/lib/shiplog/classes.rb +29 -1
- data/lib/shiplog/configuration.rb +245 -3
- data/lib/shiplog/engine.rb +3 -0
- data/lib/shiplog/github/client.rb +42 -9
- data/lib/shiplog/github/errors.rb +3 -0
- data/lib/shiplog/github/queries.rb +44 -1
- data/lib/shiplog/version.rb +1 -1
- data/lib/shiplog.rb +73 -0
- data/lib/tasks/shiplog.rake +29 -0
- metadata +48 -1
data/config/locales/en.yml
CHANGED
|
@@ -19,6 +19,18 @@ en:
|
|
|
19
19
|
roadmap:
|
|
20
20
|
title: Roadmap
|
|
21
21
|
lede: What we're working on and what comes next.
|
|
22
|
+
parts:
|
|
23
|
+
one: Includes %{count} part
|
|
24
|
+
other: Includes %{count} parts
|
|
25
|
+
shipped_heading: Recently shipped
|
|
26
|
+
shipped_date_format: "%-d %B"
|
|
27
|
+
full_changelog: See the full changelog
|
|
28
|
+
footnote: ""
|
|
29
|
+
suggest: Suggest a feature
|
|
30
|
+
switcher:
|
|
31
|
+
label: Product updates
|
|
32
|
+
roadmap: Roadmap
|
|
33
|
+
changelog: Changelog
|
|
22
34
|
changelog:
|
|
23
35
|
title: Changelog
|
|
24
36
|
lede: New features and improvements, as they ship.
|
|
@@ -26,12 +38,69 @@ en:
|
|
|
26
38
|
label: Pagination
|
|
27
39
|
older: Older
|
|
28
40
|
newer: Newer
|
|
41
|
+
search:
|
|
42
|
+
label: Search the changelog
|
|
43
|
+
submit: Search
|
|
44
|
+
summary:
|
|
45
|
+
one: "%{count} result for “%{query}”"
|
|
46
|
+
other: "%{count} results for “%{query}”"
|
|
47
|
+
clear: Clear search
|
|
48
|
+
empty: "No entries match “%{query}”."
|
|
49
|
+
areas:
|
|
50
|
+
label: Filter by area
|
|
51
|
+
all: All
|
|
52
|
+
permalink:
|
|
53
|
+
title: "%{title} · %{changelog}"
|
|
54
|
+
back: "← Back to the changelog"
|
|
55
|
+
nav_label: More changelog entries
|
|
56
|
+
newer: "← Newer: %{title}"
|
|
57
|
+
older: "Older: %{title} →"
|
|
58
|
+
feed:
|
|
59
|
+
title_with_product: "%{product} changelog"
|
|
60
|
+
link_title: Changelog (Atom)
|
|
61
|
+
subscribe: Subscribe (Atom)
|
|
29
62
|
admin:
|
|
30
63
|
title: Shiplog admin
|
|
31
64
|
nav:
|
|
32
65
|
drafts: Drafts
|
|
33
66
|
board: Roadmap board
|
|
34
67
|
sync: Sync
|
|
68
|
+
areas: Areas
|
|
69
|
+
areas:
|
|
70
|
+
title: Product areas
|
|
71
|
+
help: The AI groups entries into areas (at most %{max}) while it rewrites them. Visitors can filter the changelog by area once two areas have published entries.
|
|
72
|
+
detect: Detect areas
|
|
73
|
+
recheck: Re-check unplaced entries
|
|
74
|
+
recheck_help: Ask the AI again about entries it left without an area, e.g. after renaming, merging or adding areas.
|
|
75
|
+
no_rewriter: Detection needs config.rewriter, which is not set.
|
|
76
|
+
last_detection: "Last detection: %{time}, assigned %{count}"
|
|
77
|
+
last_error: "Last detection failed (%{time}): %{error}"
|
|
78
|
+
detection_queued: Detection queued. Refresh in a moment.
|
|
79
|
+
translate_names: Translate names
|
|
80
|
+
translate_names_help: Ask the AI for the names that are missing in some language. Names that are already there, including ones you edited, are kept.
|
|
81
|
+
no_locales: Translating names needs config.locales, which is empty.
|
|
82
|
+
no_rewriter_translate: Translating names needs config.rewriter, which is not set.
|
|
83
|
+
translation_queued:
|
|
84
|
+
one: Translation queued for %{count} area. Refresh in a moment.
|
|
85
|
+
other: Translation queued for %{count} areas. Refresh in a moment.
|
|
86
|
+
empty: No areas yet. Detect areas to propose some from your entries.
|
|
87
|
+
columns:
|
|
88
|
+
name: Name
|
|
89
|
+
entries: Entries
|
|
90
|
+
order: Order
|
|
91
|
+
merge: Merge into
|
|
92
|
+
name_label: Name
|
|
93
|
+
rename: Rename
|
|
94
|
+
renamed: Area renamed.
|
|
95
|
+
move_up: Move up
|
|
96
|
+
move_down: Move down
|
|
97
|
+
merge: Merge
|
|
98
|
+
merge_into: Merge into
|
|
99
|
+
merged: "%{from} merged into %{into}."
|
|
100
|
+
merge_target: Choose another area to merge into.
|
|
101
|
+
merge_help: Merging moves the entries to the other area and deletes this one. Deleting an area leaves its entries without one.
|
|
102
|
+
delete: Delete
|
|
103
|
+
deleted: Area deleted. Its entries have no area now.
|
|
35
104
|
entries:
|
|
36
105
|
title: Entries
|
|
37
106
|
filters: Filter entries
|
|
@@ -53,6 +122,8 @@ en:
|
|
|
53
122
|
restore: Restore
|
|
54
123
|
save: Save
|
|
55
124
|
regenerate: Regenerate
|
|
125
|
+
no_area: None
|
|
126
|
+
area_gone: no longer exists
|
|
56
127
|
regenerate_warning: Regenerating unpublishes this entry until re-approved.
|
|
57
128
|
source_changed: GitHub text changed since this draft
|
|
58
129
|
rewrite_error: Rewrite failed
|
|
@@ -60,6 +131,39 @@ en:
|
|
|
60
131
|
public_text: Public text
|
|
61
132
|
source: GitHub source
|
|
62
133
|
back: Back to drafts
|
|
134
|
+
images:
|
|
135
|
+
title: Screenshots
|
|
136
|
+
help: Shown under the text on the changelog (the first one in the list, all of them on the entry's page). Taken from the GitHub issue or pull request when the draft is written; you can also upload your own.
|
|
137
|
+
empty: No screenshots yet.
|
|
138
|
+
alt: Alt text
|
|
139
|
+
alt_placeholder: Describe the image (defaults to the title)
|
|
140
|
+
save_alt: Save alt text
|
|
141
|
+
remove: Remove
|
|
142
|
+
move_up: Up
|
|
143
|
+
move_down: Down
|
|
144
|
+
upload: Upload images
|
|
145
|
+
upload_label: Images (PNG, JPEG, GIF or WebP, up to 5 MB each)
|
|
146
|
+
none_selected: Choose at least one image.
|
|
147
|
+
rejected: "Not added, only PNG, JPEG, GIF and WebP images up to 5 MB and 10,000 pixels a side are accepted: %{names}"
|
|
148
|
+
added:
|
|
149
|
+
one: Image added.
|
|
150
|
+
other: "%{count} images added."
|
|
151
|
+
alt_saved: Alt text saved.
|
|
152
|
+
removed: Image removed.
|
|
153
|
+
moved: Image moved.
|
|
154
|
+
translations:
|
|
155
|
+
title: Translations
|
|
156
|
+
help: "Approving an entry translates it automatically, and the translation is published with the English text. A translation you edit is kept until the English text changes; then it is translated again. A stale or missing translation is not shown: visitors see the English text."
|
|
157
|
+
not_approved: Translations are written when the entry is approved.
|
|
158
|
+
missing: Missing
|
|
159
|
+
stale: Stale
|
|
160
|
+
current: Up to date
|
|
161
|
+
edited: Edited by an admin
|
|
162
|
+
retranslate: Retranslate
|
|
163
|
+
saved: Translation saved.
|
|
164
|
+
queued: Translation queued. Refresh in a moment.
|
|
165
|
+
only_approved: Only approved entries are translated.
|
|
166
|
+
no_rewriter: Translating needs config.rewriter, which is not set.
|
|
63
167
|
category_options:
|
|
64
168
|
feature: New feature
|
|
65
169
|
change: Improvement
|
|
@@ -81,6 +185,7 @@ en:
|
|
|
81
185
|
body: Text
|
|
82
186
|
released_on: Released on
|
|
83
187
|
category: Category
|
|
188
|
+
area: Area
|
|
84
189
|
reason: Reason
|
|
85
190
|
board:
|
|
86
191
|
title: Roadmap board
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Textos de Shiplog en español. Los hosts pueden sobrescribir cualquier clave en sus propios archivos de idioma.
|
|
2
|
+
es:
|
|
3
|
+
activerecord:
|
|
4
|
+
attributes:
|
|
5
|
+
shiplog/entry:
|
|
6
|
+
changelog_kind: Categoría
|
|
7
|
+
# Los nombres de los meses que usa el formato de fecha de Shiplog (rails-i18n los trae también; son los mismos).
|
|
8
|
+
date:
|
|
9
|
+
month_names: [~, enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre, noviembre, diciembre]
|
|
10
|
+
shiplog:
|
|
11
|
+
columns:
|
|
12
|
+
in_progress: En desarrollo
|
|
13
|
+
coming_soon: Próximamente
|
|
14
|
+
later: Más adelante
|
|
15
|
+
in_progress_description: Lo que estamos construyendo ahora
|
|
16
|
+
coming_soon_description: Lo siguiente en la lista
|
|
17
|
+
later_description: En nuestro radar
|
|
18
|
+
categories:
|
|
19
|
+
feature: Nuevo
|
|
20
|
+
change: Mejorado
|
|
21
|
+
empty: Todavía no hay nada
|
|
22
|
+
date_format: "%-d de %B de %Y"
|
|
23
|
+
roadmap:
|
|
24
|
+
title: Hoja de ruta
|
|
25
|
+
lede: En qué estamos trabajando y qué viene después.
|
|
26
|
+
parts:
|
|
27
|
+
one: Incluye %{count} parte
|
|
28
|
+
other: Incluye %{count} partes
|
|
29
|
+
shipped_heading: Lanzado recientemente
|
|
30
|
+
shipped_date_format: "%-d de %B"
|
|
31
|
+
full_changelog: Ver el registro de cambios completo
|
|
32
|
+
footnote: ""
|
|
33
|
+
suggest: Sugerir una función
|
|
34
|
+
switcher:
|
|
35
|
+
label: Actualizaciones del producto
|
|
36
|
+
roadmap: Hoja de ruta
|
|
37
|
+
changelog: Registro de cambios
|
|
38
|
+
changelog:
|
|
39
|
+
title: Registro de cambios
|
|
40
|
+
lede: Nuevas funciones y mejoras, a medida que se lanzan.
|
|
41
|
+
pagination:
|
|
42
|
+
label: Paginación
|
|
43
|
+
older: Anteriores
|
|
44
|
+
newer: Más recientes
|
|
45
|
+
search:
|
|
46
|
+
label: Buscar en el registro de cambios
|
|
47
|
+
submit: Buscar
|
|
48
|
+
summary:
|
|
49
|
+
one: "%{count} resultado para “%{query}”"
|
|
50
|
+
other: "%{count} resultados para “%{query}”"
|
|
51
|
+
clear: Borrar búsqueda
|
|
52
|
+
empty: "Ninguna entrada coincide con “%{query}”."
|
|
53
|
+
areas:
|
|
54
|
+
label: Filtrar por área
|
|
55
|
+
all: Todas
|
|
56
|
+
permalink:
|
|
57
|
+
title: "%{title} · %{changelog}"
|
|
58
|
+
back: "← Volver al registro de cambios"
|
|
59
|
+
nav_label: Más cambios
|
|
60
|
+
newer: "← Más reciente: %{title}"
|
|
61
|
+
older: "Anterior: %{title} →"
|
|
62
|
+
feed:
|
|
63
|
+
title_with_product: "Registro de cambios de %{product}"
|
|
64
|
+
link_title: Registro de cambios (Atom)
|
|
65
|
+
subscribe: Suscribirse (Atom)
|
|
66
|
+
admin:
|
|
67
|
+
title: Administración de Shiplog
|
|
68
|
+
nav:
|
|
69
|
+
drafts: Borradores
|
|
70
|
+
board: Tablero de la hoja de ruta
|
|
71
|
+
sync: Sincronización
|
|
72
|
+
areas: Áreas
|
|
73
|
+
areas:
|
|
74
|
+
title: Áreas del producto
|
|
75
|
+
help: La IA agrupa las entradas en áreas (como máximo %{max}) mientras las reescribe. Los visitantes pueden filtrar el registro de cambios por área cuando hay dos áreas con entradas publicadas.
|
|
76
|
+
detect: Detectar áreas
|
|
77
|
+
recheck: Revisar de nuevo las entradas sin área
|
|
78
|
+
recheck_help: Vuelve a preguntar a la IA por las entradas que dejó sin área, por ejemplo después de renombrar, fusionar o añadir áreas.
|
|
79
|
+
no_rewriter: La detección necesita config.rewriter, que no está configurado.
|
|
80
|
+
last_detection: "Última detección: %{time}, %{count} asignadas"
|
|
81
|
+
last_error: "La última detección falló (%{time}): %{error}"
|
|
82
|
+
detection_queued: Detección en cola. Actualiza en un momento.
|
|
83
|
+
translate_names: Traducir nombres
|
|
84
|
+
translate_names_help: Pide a la IA los nombres que faltan en algún idioma. Los nombres que ya existen, incluidos los que editaste, se conservan.
|
|
85
|
+
no_locales: Traducir los nombres necesita config.locales, que está vacío.
|
|
86
|
+
no_rewriter_translate: Traducir los nombres necesita config.rewriter, que no está configurado.
|
|
87
|
+
translation_queued:
|
|
88
|
+
one: Traducción en cola para %{count} área. Actualiza en un momento.
|
|
89
|
+
other: Traducción en cola para %{count} áreas. Actualiza en un momento.
|
|
90
|
+
empty: Todavía no hay áreas. Detecta áreas para que se propongan a partir de tus entradas.
|
|
91
|
+
columns:
|
|
92
|
+
name: Nombre
|
|
93
|
+
entries: Entradas
|
|
94
|
+
order: Orden
|
|
95
|
+
merge: Fusionar con
|
|
96
|
+
name_label: Nombre
|
|
97
|
+
rename: Renombrar
|
|
98
|
+
renamed: Área renombrada.
|
|
99
|
+
move_up: Subir
|
|
100
|
+
move_down: Bajar
|
|
101
|
+
merge: Fusionar
|
|
102
|
+
merge_into: Fusionar con
|
|
103
|
+
merged: "%{from} se fusionó con %{into}."
|
|
104
|
+
merge_target: Elige otra área con la que fusionar.
|
|
105
|
+
merge_help: Al fusionar, las entradas pasan a la otra área y esta se elimina. Si eliminas un área, sus entradas se quedan sin área.
|
|
106
|
+
delete: Eliminar
|
|
107
|
+
deleted: Área eliminada. Sus entradas ya no tienen área.
|
|
108
|
+
entries:
|
|
109
|
+
title: Entradas
|
|
110
|
+
filters: Filtrar entradas
|
|
111
|
+
all_kinds: Todos los tipos
|
|
112
|
+
empty: Ninguna entrada coincide.
|
|
113
|
+
pagination: Paginación
|
|
114
|
+
older: Anteriores
|
|
115
|
+
newer: Más recientes
|
|
116
|
+
saved: Entrada guardada.
|
|
117
|
+
approved: Entrada aprobada.
|
|
118
|
+
discarded: Entrada descartada.
|
|
119
|
+
restored: Entrada devuelta a borrador.
|
|
120
|
+
invalid_transition: Esa acción no está disponible para esta entrada en su estado actual.
|
|
121
|
+
rewrite_queued: Reescritura en cola. Actualiza en un momento.
|
|
122
|
+
edit: Editar
|
|
123
|
+
edit_title: "Editar %{kind}"
|
|
124
|
+
approve: Aprobar
|
|
125
|
+
discard: Descartar
|
|
126
|
+
restore: Restaurar
|
|
127
|
+
save: Guardar
|
|
128
|
+
regenerate: Regenerar
|
|
129
|
+
no_area: Ninguna
|
|
130
|
+
area_gone: ya no existe
|
|
131
|
+
regenerate_warning: Al regenerar, esta entrada deja de estar publicada hasta que se apruebe de nuevo.
|
|
132
|
+
source_changed: El texto de GitHub cambió desde este borrador
|
|
133
|
+
rewrite_error: Falló la reescritura
|
|
134
|
+
not_rewritten: Todavía sin reescribir
|
|
135
|
+
public_text: Texto público
|
|
136
|
+
source: Origen en GitHub
|
|
137
|
+
back: Volver a los borradores
|
|
138
|
+
images:
|
|
139
|
+
title: Capturas de pantalla
|
|
140
|
+
help: Se muestran bajo el texto en el registro de cambios (la primera en la lista, todas en la página de la entrada). Se toman de la incidencia o del pull request de GitHub al escribir el borrador; también puedes subir las tuyas.
|
|
141
|
+
empty: Todavía no hay capturas.
|
|
142
|
+
alt: Texto alternativo
|
|
143
|
+
alt_placeholder: Describe la imagen (por defecto, el título)
|
|
144
|
+
save_alt: Guardar texto alternativo
|
|
145
|
+
remove: Quitar
|
|
146
|
+
move_up: Subir
|
|
147
|
+
move_down: Bajar
|
|
148
|
+
upload: Subir imágenes
|
|
149
|
+
upload_label: Imágenes (PNG, JPEG, GIF o WebP, hasta 5 MB cada una)
|
|
150
|
+
none_selected: Elige al menos una imagen.
|
|
151
|
+
rejected: "No se añadieron; solo se aceptan imágenes PNG, JPEG, GIF y WebP de hasta 5 MB y 10.000 píxeles por lado: %{names}"
|
|
152
|
+
added:
|
|
153
|
+
one: Imagen añadida.
|
|
154
|
+
other: "%{count} imágenes añadidas."
|
|
155
|
+
alt_saved: Texto alternativo guardado.
|
|
156
|
+
removed: Imagen quitada.
|
|
157
|
+
moved: Imagen movida.
|
|
158
|
+
translations:
|
|
159
|
+
title: Traducciones
|
|
160
|
+
help: "Al aprobar una entrada, esta se traduce automáticamente, y la traducción se publica junto con el texto en inglés. Una traducción que edites se conserva hasta que cambie el texto en inglés; entonces se vuelve a traducir. Una traducción desactualizada o ausente no se muestra: los visitantes ven el texto en inglés."
|
|
161
|
+
not_approved: Las traducciones se escriben cuando se aprueba la entrada.
|
|
162
|
+
missing: Falta
|
|
163
|
+
stale: Desactualizada
|
|
164
|
+
current: Al día
|
|
165
|
+
edited: Editada por un administrador
|
|
166
|
+
retranslate: Traducir de nuevo
|
|
167
|
+
saved: Traducción guardada.
|
|
168
|
+
queued: Traducción en cola. Actualiza en un momento.
|
|
169
|
+
only_approved: Solo se traducen las entradas aprobadas.
|
|
170
|
+
no_rewriter: Para traducir hace falta config.rewriter, que no está configurado.
|
|
171
|
+
category_options:
|
|
172
|
+
feature: Nueva función
|
|
173
|
+
change: Mejora
|
|
174
|
+
statuses:
|
|
175
|
+
draft: Borradores
|
|
176
|
+
approved: Aprobadas
|
|
177
|
+
discarded: Descartadas
|
|
178
|
+
kinds:
|
|
179
|
+
roadmap: Hoja de ruta
|
|
180
|
+
feature: Función
|
|
181
|
+
change: Cambio
|
|
182
|
+
columns:
|
|
183
|
+
entry: Entrada
|
|
184
|
+
kind: Tipo
|
|
185
|
+
source: Origen
|
|
186
|
+
actions: Acciones
|
|
187
|
+
fields:
|
|
188
|
+
title: Título
|
|
189
|
+
body: Texto
|
|
190
|
+
released_on: Fecha de lanzamiento
|
|
191
|
+
category: Categoría
|
|
192
|
+
area: Área
|
|
193
|
+
reason: Motivo
|
|
194
|
+
board:
|
|
195
|
+
title: Tablero de la hoja de ruta
|
|
196
|
+
help: Arrastra las tarjetas entre columnas para fijarlas y ordenarlas. Sin JavaScript, usa el botón Mover de cada tarjeta.
|
|
197
|
+
updated: Tablero actualizado.
|
|
198
|
+
not_approved: Sin aprobar
|
|
199
|
+
pinned: Fijada
|
|
200
|
+
move_to: Mover a
|
|
201
|
+
move: Mover
|
|
202
|
+
unpin: Quitar de fijadas
|
|
203
|
+
sync:
|
|
204
|
+
title: Estado de la sincronización
|
|
205
|
+
queued: Sincronización en cola.
|
|
206
|
+
webhook_secret_missing: El secreto del webhook no está configurado, así que se rechazan los webhooks de GitHub.
|
|
207
|
+
github_token_missing: El token de GitHub no está configurado, así que no se puede sincronizar.
|
|
208
|
+
sync_now: Sincronizar ahora
|
|
209
|
+
sync_and_scan: Sincronizar y buscar cambios
|
|
210
|
+
repositories: Repositorios
|
|
211
|
+
no_repositories: No hay repositorios configurados.
|
|
212
|
+
repository: Repositorio
|
|
213
|
+
synced_at: Última sincronización
|
|
214
|
+
changes_scanned_at: Cambios revisados
|
|
215
|
+
last_error: Último error
|
|
216
|
+
never: Nunca
|
|
217
|
+
deliveries: Últimas entregas de webhook
|
|
218
|
+
no_deliveries: Todavía no hay entregas.
|
|
219
|
+
event: Evento
|
|
220
|
+
action: Acción
|
|
221
|
+
received_at: Recibida
|
|
222
|
+
processed_at: Procesada
|
|
223
|
+
error: Error
|
data/config/routes.rb
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
Shiplog::Engine.routes.draw do
|
|
2
2
|
get Shiplog.config.roadmap_path, to: "roadmaps#show", as: :roadmap
|
|
3
|
+
# The feed and the permalinks come before the plain changelog route, whose optional (.:format) would
|
|
4
|
+
# otherwise take /changelog.atom. A slug has no dot, and the permalink takes no format.
|
|
5
|
+
get "#{Shiplog.config.changelog_path}.atom", to: "changelog_feeds#show", as: :changelog_feed, defaults: { format: "atom" }
|
|
6
|
+
get "#{Shiplog.config.changelog_path}/:slug", to: "changelog_entries#show", as: :changelog_entry,
|
|
7
|
+
format: false, constraints: { slug: /[a-z0-9-]+/ }
|
|
3
8
|
get Shiplog.config.changelog_path, to: "changelogs#show", as: :changelog
|
|
4
9
|
post "shiplog/github/webhook", to: "webhooks#create", as: :github_webhook
|
|
5
10
|
get "shiplog/assets/:version/:name", to: "frontends#show", as: :frontend, constraints: { version: /[^\/]+/, name: /[a-z_]+\.(css|js)/ }
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class CreateShiplogPullRequestUpgrades < ActiveRecord::Migration[8.1]
|
|
2
|
+
def change
|
|
3
|
+
# What upgrade detection needs from the pull request, and its "checked" marker: a pull request with
|
|
4
|
+
# no tracked upgrade has no upgrade row, so only a column can say "inspected, nothing found".
|
|
5
|
+
change_table :shiplog_pull_requests do |t|
|
|
6
|
+
t.string :base_oid
|
|
7
|
+
t.string :merge_oid
|
|
8
|
+
t.boolean :lockfile_changed, null: false, default: false
|
|
9
|
+
t.datetime :upgrades_checked_at
|
|
10
|
+
# Transient failures while inspecting it; the detector gives up (marks it checked) after a few.
|
|
11
|
+
t.integer :upgrade_check_attempts, null: false, default: 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
create_table :shiplog_pull_request_upgrades do |t|
|
|
15
|
+
t.references :pull_request, null: false, foreign_key: { to_table: :shiplog_pull_requests }, index: false
|
|
16
|
+
t.string :gem_name, null: false
|
|
17
|
+
t.string :from_ref
|
|
18
|
+
t.string :to_ref
|
|
19
|
+
t.string :gem_repository
|
|
20
|
+
# Not `changes`: that name belongs to ActiveModel::Dirty and Active Record refuses it as an attribute.
|
|
21
|
+
t.jsonb :gem_changes, null: false, default: []
|
|
22
|
+
t.timestamps
|
|
23
|
+
t.index [ :pull_request_id, :gem_name ], unique: true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The changelog and the roadmap's recently shipped list read approved entries newest release first:
|
|
27
|
+
# `status = 'approved' ... ORDER BY released_on DESC`. Equality column first, then the sort column.
|
|
28
|
+
add_index :shiplog_entries, [ :status, :released_on ]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Everything 0.3.0 adds to the schema, one section per feature. Additive and reversible.
|
|
2
|
+
class Shiplog030 < ActiveRecord::Migration[8.1]
|
|
3
|
+
# A migration must not depend on model code that changes later: this is a bare table-backed class.
|
|
4
|
+
class MigrationEntry < ActiveRecord::Base
|
|
5
|
+
self.table_name = "shiplog_entries"
|
|
6
|
+
self.inheritance_column = nil
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
SLUG_MAX_LENGTH = 80
|
|
10
|
+
|
|
11
|
+
def change
|
|
12
|
+
# --- Entry permalinks (/changelog/:slug) ---
|
|
13
|
+
# Set when an entry is first approved, never changed afterwards, so links never break. Nil for roadmap
|
|
14
|
+
# entries and drafts. Entries approved before 0.3.0 get theirs here (oldest first, so the oldest keeps the
|
|
15
|
+
# plain slug on duplicate titles): the public pages never write, so nothing else fills them in.
|
|
16
|
+
add_column :shiplog_entries, :slug, :string
|
|
17
|
+
add_index :shiplog_entries, :slug, unique: true, where: "slug IS NOT NULL"
|
|
18
|
+
reversible do |direction|
|
|
19
|
+
direction.up do
|
|
20
|
+
MigrationEntry.reset_column_information
|
|
21
|
+
backfill_slugs
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# --- "What's new" unseen count ---
|
|
26
|
+
# `Shiplog.unseen_count` counts approved feature and change entries with `approved_at > since`:
|
|
27
|
+
# an equality column first, then the range column.
|
|
28
|
+
add_index :shiplog_entries, [ :status, :approved_at ]
|
|
29
|
+
|
|
30
|
+
# --- Product areas (detected by AI) ---
|
|
31
|
+
# `entries.area_id` is nullable; deleting an area nullifies it (merging moves the entries first).
|
|
32
|
+
# `area_set_by_admin` marks an area chosen by hand, which detection never overwrites.
|
|
33
|
+
create_table :shiplog_areas do |t|
|
|
34
|
+
t.string :name, null: false
|
|
35
|
+
t.string :slug, null: false
|
|
36
|
+
t.integer :position, null: false, default: 0
|
|
37
|
+
# The name in each of config.locales, keyed by locale string ({ "es" => "Listas de embalaje" }); empty
|
|
38
|
+
# until translated. Slugs stay English, so ?area= URLs are shared across locales.
|
|
39
|
+
t.jsonb :name_translations, null: false, default: {}
|
|
40
|
+
t.timestamps
|
|
41
|
+
end
|
|
42
|
+
add_index :shiplog_areas, :slug, unique: true
|
|
43
|
+
add_reference :shiplog_entries, :area, null: true, index: true, foreign_key: { to_table: :shiplog_areas, on_delete: :nullify }
|
|
44
|
+
add_column :shiplog_entries, :area_set_by_admin, :boolean, null: false, default: false
|
|
45
|
+
# When detection last asked the AI about the entry (placed or not): unplaced entries are not asked again
|
|
46
|
+
# until an admin asks for a re-check.
|
|
47
|
+
add_column :shiplog_entries, :area_detected_at, :datetime
|
|
48
|
+
# A small key-value store for state that belongs to no record, e.g. the result of the last area detection
|
|
49
|
+
# (shown on the admin's Areas page).
|
|
50
|
+
create_table :shiplog_settings do |t|
|
|
51
|
+
t.string :key, null: false
|
|
52
|
+
t.jsonb :value, null: false, default: {}
|
|
53
|
+
t.timestamps
|
|
54
|
+
end
|
|
55
|
+
add_index :shiplog_settings, :key, unique: true
|
|
56
|
+
|
|
57
|
+
# --- Screenshots (needs Active Storage in the host; the columns are harmless without it) ---
|
|
58
|
+
# `image_order` is the ordered list of the entry's image blob ids, `image_alts` the alt text per blob id
|
|
59
|
+
# ({ "12" => "The dark theme" }); a missing alt text falls back to the entry's title.
|
|
60
|
+
add_column :shiplog_entries, :image_order, :jsonb, null: false, default: []
|
|
61
|
+
add_column :shiplog_entries, :image_alts, :jsonb, null: false, default: {}
|
|
62
|
+
|
|
63
|
+
# --- Translations of entries (config.locales) ---
|
|
64
|
+
# One row per entry and locale, published with the English text (no second approval). `source_digest` is the
|
|
65
|
+
# digest of the English title and body it was made from: a row whose digest differs from the entry's current
|
|
66
|
+
# text is stale and never shown. `edited_by_admin` keeps an admin's edit until the English text changes.
|
|
67
|
+
create_table :shiplog_entry_translations do |t|
|
|
68
|
+
t.references :entry, null: false, index: false, foreign_key: { to_table: :shiplog_entries, on_delete: :cascade }
|
|
69
|
+
t.string :locale, null: false
|
|
70
|
+
t.string :title, null: false
|
|
71
|
+
t.text :body, null: false, default: ""
|
|
72
|
+
t.string :source_digest, null: false
|
|
73
|
+
t.boolean :edited_by_admin, null: false, default: false
|
|
74
|
+
t.timestamps
|
|
75
|
+
end
|
|
76
|
+
add_index :shiplog_entry_translations, [ :entry_id, :locale ], unique: true
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Gives every approved feature and change with a release date, and no slug, one: the title as [a-z0-9-] only
|
|
80
|
+
# (cut at 80 characters), made unique with -2, -3, ...; entry-<id> when nothing is left. The same rules as
|
|
81
|
+
# Shiplog::Entry#generate_slug at the time of 0.3.0.
|
|
82
|
+
def backfill_slugs
|
|
83
|
+
taken = MigrationEntry.where.not(slug: nil).pluck(:slug).to_set
|
|
84
|
+
MigrationEntry.where(status: "approved", kind: %w[feature change], slug: nil).where.not(released_on: nil)
|
|
85
|
+
.order(:released_on, :approved_at, :id).to_a.each do |entry|
|
|
86
|
+
slug = slug_for(entry, taken)
|
|
87
|
+
taken << slug
|
|
88
|
+
MigrationEntry.where(id: entry.id, slug: nil).update_all(slug:)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def slug_for(entry, taken)
|
|
95
|
+
base = entry.title.to_s.parameterize.tr("_", "-").squeeze("-").first(SLUG_MAX_LENGTH).gsub(/\A-+|-+\z/, "").presence || "entry-#{entry.id}"
|
|
96
|
+
candidate = base
|
|
97
|
+
suffix = 2
|
|
98
|
+
while taken.include?(candidate)
|
|
99
|
+
tail = "-#{suffix}"
|
|
100
|
+
candidate = "#{base.first(SLUG_MAX_LENGTH - tail.length).delete_suffix("-")}#{tail}"
|
|
101
|
+
suffix += 1
|
|
102
|
+
end
|
|
103
|
+
candidate
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -17,9 +17,12 @@ module Shiplog
|
|
|
17
17
|
page_header: "mb-8",
|
|
18
18
|
page_title: "text-3xl font-semibold tracking-tight",
|
|
19
19
|
page_lede: "mt-2 text-gray-600 dark:text-gray-400",
|
|
20
|
+
switcher: "mt-6 inline-flex gap-1 rounded-full bg-gray-100 p-1 text-sm font-medium dark:bg-gray-900",
|
|
21
|
+
switcher_link: "rounded-full px-4 py-1.5 text-gray-600 transition-colors hover:text-gray-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 aria-[current=page]:bg-white aria-[current=page]:text-gray-900 aria-[current=page]:shadow-sm dark:text-gray-400 dark:hover:text-white dark:aria-[current=page]:bg-gray-700 dark:aria-[current=page]:text-white",
|
|
20
22
|
columns: "grid gap-6 md:grid-cols-3",
|
|
21
23
|
column: "rounded-xl border border-gray-200 bg-gray-50 p-4 dark:border-gray-800 dark:bg-gray-900/50",
|
|
22
24
|
column_header: "mb-4 border-b border-gray-200 pb-3 dark:border-gray-800",
|
|
25
|
+
column_marker: "mr-2 inline-block h-2 w-2 rounded-full bg-gray-400 in-[.shiplog-column--in-progress]:bg-indigo-600 in-[.shiplog-column--coming-soon]:bg-indigo-300",
|
|
23
26
|
column_title: "inline text-base font-semibold",
|
|
24
27
|
column_count: "ml-2 rounded-full bg-gray-200 px-2 py-0.5 text-xs font-medium text-gray-700 dark:bg-gray-800 dark:text-gray-300",
|
|
25
28
|
column_description: "mt-1 text-sm text-gray-500 dark:text-gray-400",
|
|
@@ -28,6 +31,16 @@ module Shiplog
|
|
|
28
31
|
card: "rounded-lg border border-gray-200 bg-white p-3 shadow-sm transition hover:border-indigo-400 hover:shadow dark:border-gray-800 dark:bg-gray-900 dark:hover:border-indigo-500",
|
|
29
32
|
card_title: "font-medium",
|
|
30
33
|
card_body: "mt-1 text-sm text-gray-600 dark:text-gray-400",
|
|
34
|
+
card_meta: "mt-3 flex flex-wrap items-center gap-2 text-xs font-medium text-gray-500 dark:text-gray-400",
|
|
35
|
+
card_tag: "rounded-md bg-gray-100 px-2 py-0.5 text-gray-700 dark:bg-white/10 dark:text-gray-300",
|
|
36
|
+
shipped: "mt-12 grid grid-cols-[1fr_auto] items-baseline gap-x-6 gap-y-4 border-t border-gray-200 pt-8 dark:border-gray-800",
|
|
37
|
+
shipped_title: "text-lg font-semibold",
|
|
38
|
+
shipped_list: "col-span-2 grid gap-6 sm:grid-cols-2 lg:grid-cols-4",
|
|
39
|
+
shipped_item: "flex flex-col gap-1",
|
|
40
|
+
shipped_date: "text-xs tabular-nums text-gray-500 dark:text-gray-400",
|
|
41
|
+
shipped_link: "text-sm font-semibold text-gray-900 hover:text-indigo-600 dark:text-white dark:hover:text-indigo-400",
|
|
42
|
+
footnote: "mt-10 border-t border-gray-200 pt-6 text-center text-sm text-gray-500 dark:border-gray-800 dark:text-gray-400",
|
|
43
|
+
footnote_link: "font-medium text-indigo-600 hover:underline dark:text-indigo-400",
|
|
31
44
|
months: "space-y-10",
|
|
32
45
|
month: "border-l-2 border-gray-200 pl-6 dark:border-gray-800",
|
|
33
46
|
month_title: "mb-4 text-lg font-semibold",
|
|
@@ -40,7 +53,22 @@ module Shiplog
|
|
|
40
53
|
entry_date: "text-xs text-gray-500 dark:text-gray-400",
|
|
41
54
|
pagination: "mt-8 flex justify-between",
|
|
42
55
|
pagination_link: "text-sm font-medium text-indigo-600 hover:underline dark:text-indigo-400",
|
|
43
|
-
empty: "text-gray-500 dark:text-gray-400"
|
|
56
|
+
empty: "text-gray-500 dark:text-gray-400",
|
|
57
|
+
search: "my-4 flex gap-2",
|
|
58
|
+
search_input: "min-w-0 flex-1 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm dark:border-gray-700 dark:bg-gray-900",
|
|
59
|
+
search_button: "rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-indigo-500",
|
|
60
|
+
search_summary: "mb-4 text-sm text-gray-500 dark:text-gray-400",
|
|
61
|
+
search_clear: "ml-2 font-medium text-indigo-600 hover:underline dark:text-indigo-400",
|
|
62
|
+
search_empty: "text-gray-500 dark:text-gray-400",
|
|
63
|
+
permalink: "mx-auto max-w-2xl rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-800 dark:bg-gray-900",
|
|
64
|
+
permalink_back: "mt-6 inline-block text-sm font-medium text-indigo-600 hover:underline dark:text-indigo-400",
|
|
65
|
+
permalink_nav: "mt-8 flex flex-wrap justify-between gap-4 border-t border-gray-200 pt-4 dark:border-gray-800",
|
|
66
|
+
permalink_nav_link: "text-sm font-medium text-indigo-600 hover:underline dark:text-indigo-400",
|
|
67
|
+
areas: "my-4 flex flex-wrap gap-2",
|
|
68
|
+
area_link: "rounded-full border border-gray-300 px-3 py-0.5 text-sm hover:border-indigo-500 dark:border-gray-700 [&.shiplog-areas__link--current]:border-indigo-600 [&.shiplog-areas__link--current]:bg-indigo-600 [&.shiplog-areas__link--current]:text-white",
|
|
69
|
+
entry_area: "text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400",
|
|
70
|
+
entry_images: "mt-3 grid w-full gap-3",
|
|
71
|
+
entry_image: "h-auto max-w-full rounded-lg border border-gray-200 dark:border-gray-800"
|
|
44
72
|
}.freeze
|
|
45
73
|
|
|
46
74
|
def copy_initializer
|
|
@@ -2,6 +2,21 @@ Shiplog.configure do |config|
|
|
|
2
2
|
# GitHub repositories to sync ("owner/name"). Sub-issues may cross repositories of the same owner.
|
|
3
3
|
config.repositories = %w[acme/app acme/app-ios]
|
|
4
4
|
|
|
5
|
+
# A repository can also be a Hash with options:
|
|
6
|
+
# changelog: false keep the repository on the roadmap, but never draft changelog entries from its PRs or commits
|
|
7
|
+
# gem: "name" the gem's name in your Gemfile.lock. When a merged PR upgrades it, the changelog gets one
|
|
8
|
+
# entry for the upgrade, built from the gem's changes. Needed because names differ
|
|
9
|
+
# (a "trackberry-produce" gem can live in acme/produce) and a public gem of the same name
|
|
10
|
+
# is not your repository.
|
|
11
|
+
# config.repositories = [
|
|
12
|
+
# "acme/app",
|
|
13
|
+
# { name: "acme/app-ios" },
|
|
14
|
+
# { name: "acme/pricing", changelog: false, gem: "acme-pricing" }
|
|
15
|
+
# ]
|
|
16
|
+
|
|
17
|
+
# Lockfile read in merged pull requests to detect gem upgrades (change it for a monorepo).
|
|
18
|
+
# config.lockfile_path = "Gemfile.lock"
|
|
19
|
+
|
|
5
20
|
# A String, or a callable evaluated on every GitHub request (e.g. to mint a GitHub App installation token).
|
|
6
21
|
config.github_token = -> { Rails.application.credentials.dig(:github, :shiplog_token) }
|
|
7
22
|
|
|
@@ -82,5 +97,71 @@ Shiplog.configure do |config|
|
|
|
82
97
|
|
|
83
98
|
# Public paths, read when routes are drawn.
|
|
84
99
|
# config.roadmap_path = "roadmap"
|
|
85
|
-
# config.changelog_path = "changelog"
|
|
100
|
+
# config.changelog_path = "changelog" # a-z, 0-9, - and _; "docs/news" nests; outer slashes are stripped
|
|
101
|
+
|
|
102
|
+
# The site's canonical origin (scheme, host, optional port; no path). The Atom feed's ids and links, og:url
|
|
103
|
+
# and the other absolute URLs use it instead of the request's host, which varies (apex vs www, a forged
|
|
104
|
+
# X-Forwarded-Host). Behind a proxy, also set config.assume_ssl = true (or send X-Forwarded-Proto) in Rails.
|
|
105
|
+
# config.canonical_url = "https://example.com"
|
|
106
|
+
|
|
107
|
+
# Pages added to the Roadmap / Changelog switcher. label and path are Strings, or callables evaluated in the
|
|
108
|
+
# view (route helpers, I18n). Render the same switcher on your own pages with `helper Shiplog::SwitcherHelper`
|
|
109
|
+
# and `<%%= shiplog_switcher %>`.
|
|
110
|
+
# config.extra_pages = [ { label: "News", path: -> { main_app.news_path } } ]
|
|
111
|
+
|
|
112
|
+
# Names shown on roadmap cards for the repository an item lives in (Strings or callables).
|
|
113
|
+
# config.repository_labels = { "acme/app-ios" => "iPhone & iPad" }
|
|
114
|
+
|
|
115
|
+
# How many recently shipped changelog entries the roadmap lists; 0 hides the section.
|
|
116
|
+
# config.roadmap_shipped_count = 4
|
|
117
|
+
|
|
118
|
+
# Where the roadmap's "Suggest a feature" link goes (String or callable); no link while nil. Add a footnote
|
|
119
|
+
# next to it with the shiplog.roadmap.footnote translation.
|
|
120
|
+
# config.feedback_path = -> { main_app.new_feedback_path }
|
|
121
|
+
|
|
122
|
+
# The public changelog's search box and ?q= filtering. Set to false to turn search off.
|
|
123
|
+
# config.changelog_search = true
|
|
124
|
+
|
|
125
|
+
# "What's new". Shiplog doesn't know your users, so you supply the "last seen" time. This is called with the
|
|
126
|
+
# controller on every changelog index or permalink view, BEFORE the page renders (a 304 revisit included), so a
|
|
127
|
+
# navbar badge in the same response is current. It may write and runs on every visit: keep it cheap, and write
|
|
128
|
+
# only when something is new. Show `Shiplog.unseen_count(since: user.changelog_seen_at)` (at most 99, counted on
|
|
129
|
+
# approved_at; `helper Shiplog::UnseenHelper` and `shiplog_unseen_count(since)` in views) next to your Changelog
|
|
130
|
+
# link. current_user is often private, hence controller.send (or read a Current attribute).
|
|
131
|
+
# config.on_changelog_seen = lambda do |controller|
|
|
132
|
+
# user = controller.send(:current_user)
|
|
133
|
+
# user.update_column(:changelog_seen_at, Time.current) if user && Shiplog.unseen_count(since: user.changelog_seen_at).positive?
|
|
134
|
+
# end
|
|
135
|
+
|
|
136
|
+
# The 0.3.0 migration gives entries approved so far their permalink slug. The public pages never write (a GET
|
|
137
|
+
# may hit a read replica), so an entry approved by older code during a deploy window has no permalink until
|
|
138
|
+
# `bin/rails shiplog:backfill_slugs` runs. Permalink pages set `content_for :shiplog_og` (Open Graph tags),
|
|
139
|
+
# `content_for :shiplog_description` and `content_for :shiplog_feed` (the Atom discovery link); Shiplog's own
|
|
140
|
+
# layout renders them, so emit them in your layout's <head> when you set `config.public_layout`.
|
|
141
|
+
|
|
142
|
+
# Product areas. The rewriter's reply may name an area (an existing one, or a new name of 1-3 words); Shiplog
|
|
143
|
+
# creates it while fewer than max_areas exist, so the AI cannot sprawl. The changelog offers an area filter
|
|
144
|
+
# (?area=slug) once two areas have published entries. Manage areas in the admin ("Areas"): rename, reorder,
|
|
145
|
+
# merge, delete, and "Detect areas" to backfill entries that have none (it reuses config.rewriter).
|
|
146
|
+
# Entries you set by hand on the edit page are never changed by the AI.
|
|
147
|
+
# config.max_areas = 8
|
|
148
|
+
|
|
149
|
+
# Screenshots in entries. They need Active Storage in your app (require "active_storage/engine", and its tables);
|
|
150
|
+
# without it they stay off and Shiplog logs that once at boot. When a draft is written, the images in the GitHub
|
|
151
|
+
# issue or pull request body are attached to the entry (GitHub image hosts only, 5 MB and PNG, JPEG, GIF or
|
|
152
|
+
# WebP at most; the token needs no extra permission). You can also upload images on the entry edit page.
|
|
153
|
+
# config.images = true
|
|
154
|
+
# config.max_images_per_entry = 4
|
|
155
|
+
|
|
156
|
+
# Translations of entries. Entries are translated into each of these locales with config.rewriter when they are
|
|
157
|
+
# approved, and again when the English title or body of an approved entry changes; the translation is published
|
|
158
|
+
# at once, with no second approval. One LLM call per entry, locale and change. Admins can edit a translation on
|
|
159
|
+
# the entry page (kept until the English text changes) or retranslate it. Pages render the translation when
|
|
160
|
+
# I18n.locale is one of these and it matches the current English text, and English otherwise. Your routes
|
|
161
|
+
# decide which URLs set the locale (e.g. a /es scope). The default locale is dropped from the list.
|
|
162
|
+
# config.locales = [] # e.g. [:es]
|
|
163
|
+
|
|
164
|
+
# Callables above cannot be part of the public pages' ETag. Bump this when the output of a callable you
|
|
165
|
+
# configured changes (a new label, another path) so cached pages are refreshed.
|
|
166
|
+
# config.cache_version = nil
|
|
86
167
|
end
|