trmnl_preview 0.9.0 → 0.10.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 +5 -0
- data/README.md +2 -0
- data/lib/trmnlp/commands/list.rb +47 -5
- data/lib/trmnlp/commands/push.rb +47 -5
- data/lib/trmnlp/lint/checks/description_length.rb +21 -0
- data/lib/trmnlp/lint/source.rb +1 -0
- data/lib/trmnlp/lint.rb +2 -0
- data/lib/trmnlp/version.rb +1 -1
- data/templates/init/src/settings.yml +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 445d3f901f97e586cf2bfeb3dd8286cf2b02cb3c14d8380f50f0d34d35d7d97f
|
|
4
|
+
data.tar.gz: e40390fff7ec0ca67127209eacd5de1e096fb800a91148c1068c91aa66748411
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8bd5fe746adb49697c526ff51256ece9febc2172aa5177af97399a45664f6ce2925f019ed73efdc0bb0515f2405abb45583faf27d8046feb706ccbde9c9e8c46
|
|
7
|
+
data.tar.gz: 22ec5594e73ec2903e5f6d83a0b62699cc7cc4543aca6e0bf8f8b5f376dd3418be4ba2b6d2c7d2ef7af63cedb6c451612333a00f5e6dc66dbb60f6f76383cf27
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
# Changelog
|
|
3
3
|
|
|
4
|
+
## 0.10.0
|
|
5
|
+
|
|
6
|
+
- Added support for the `description` plugin setting, an optional one-line summary of the plugin. `trmnlp init` scaffolds the key in `src/settings.yml`, `trmnlp lint` reports descriptions longer than 35 characters (the hosted service's limit), and `trmnlp list` shows a DESCRIPTION column when any plugin has one. Only the length is checked. Storing the value needs the matching hosted service release; until then `trmnlp push` drops it, because it rewrites the local `settings.yml` from the server's response.
|
|
7
|
+
- `trmnlp push` now offers to delete the server-side transform script when the project has no local `transform.*` file. Previously, deleting the file locally was a silent no-op: the server kept executing its copy and every `trmnlp pull` re-created the file. Answering yes sends `serverless_language: none` in the pushed settings.yml, which the server consumes as an explicit removal request. `--force` pushes skip the question and behave exactly as before; a failed server check never blocks the push.
|
|
8
|
+
|
|
4
9
|
## 0.9.0
|
|
5
10
|
|
|
6
11
|
- Added OAuth2 support for local plugin preview (beta). Configure a provider with the flat `oauth_*` keys in `src/settings.yml` (authorize and token URLs, scopes, optional PKCE), which round-trip through `trmnlp push` and `pull`. Set `TRMNL_OAUTH_CLIENT_ID` and `TRMNL_OAUTH_CLIENT_SECRET` in your environment (credentials stay local and are never synced), and register `http://localhost:4567/oauth/callback` as the redirect URI in your OAuth app. `trmnlp serve` shows a Connect banner that runs the authorization code flow in the browser, stores the tokens in the cache directory (never in the project), and refreshes them before they expire. The access token is exposed to polling templates as `{{ oauth_access_token }}`, matching the hosted service. This is a beta feature; please report incorrect behaviour at https://github.com/usetrmnl/trmnlp/issues.
|
data/README.md
CHANGED
|
@@ -429,6 +429,8 @@ The `settings.yml` file is part of the plugin definition, and is uploaded and do
|
|
|
429
429
|
|
|
430
430
|
`framework_version:` pins the [TRMNL Design System](https://trmnl.com/framework) version this plugin renders against — `latest` (the default) tracks the newest release, or set a specific version for reproducibility. It lives here rather than in `.trmnlp.yml` so the value round-trips with the hosted plugin service.
|
|
431
431
|
|
|
432
|
+
`description:` is an optional one-line summary of the plugin, up to 35 characters. `trmnlp lint` reports anything longer, and `trmnlp list` shows it next to each plugin name.
|
|
433
|
+
|
|
432
434
|
See [TRMNL documentation](https://help.trmnl.com/en/articles/10542599-importing-and-exporting-private-plugins#h_581fb988f0) for details on this file's contents.
|
|
433
435
|
|
|
434
436
|
|
data/lib/trmnlp/commands/list.rb
CHANGED
|
@@ -9,6 +9,8 @@ module TRMNLP
|
|
|
9
9
|
Options = Data.define(:dir, :quiet)
|
|
10
10
|
|
|
11
11
|
PRIVATE_PLUGIN_ID = 37
|
|
12
|
+
ID_WIDTH = 8
|
|
13
|
+
RULE_WIDTH = 50
|
|
12
14
|
|
|
13
15
|
def call
|
|
14
16
|
authenticate!
|
|
@@ -25,15 +27,55 @@ module TRMNLP
|
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
reporter.info "Your plugins:\n\n"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
report_table(plugins)
|
|
31
|
+
|
|
32
|
+
reporter.info "\nTo clone a plugin:"
|
|
33
|
+
reporter.info ' trmnlp clone [folder_name] [id]'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def report_table(plugins)
|
|
39
|
+
return report_names(plugins) if plugins.none? { |plugin| description(plugin) }
|
|
40
|
+
|
|
41
|
+
report_names_and_descriptions(plugins)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def report_names(plugins)
|
|
45
|
+
ids = id_width(plugins)
|
|
46
|
+
report_header format("%-#{ids}s %s", 'ID', 'NAME')
|
|
30
47
|
|
|
31
48
|
plugins.each do |plugin|
|
|
32
|
-
reporter.info format(
|
|
49
|
+
reporter.info format(" %-#{ids}s %s", plugin['id'], plugin['name'])
|
|
33
50
|
end
|
|
51
|
+
end
|
|
34
52
|
|
|
35
|
-
|
|
36
|
-
|
|
53
|
+
def report_names_and_descriptions(plugins)
|
|
54
|
+
ids = id_width(plugins)
|
|
55
|
+
names = column_width(plugins.map { |plugin| plugin['name'] }, 'NAME'.length)
|
|
56
|
+
report_header format("%-#{ids}s %-#{names}s %s", 'ID', 'NAME', 'DESCRIPTION')
|
|
57
|
+
|
|
58
|
+
plugins.each do |plugin|
|
|
59
|
+
row = format(" %-#{ids}s %-#{names}s %s", plugin['id'], plugin['name'], description(plugin))
|
|
60
|
+
reporter.info row.rstrip
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# BYOS servers return a UUID for plugins created there and the original
|
|
65
|
+
# number for plugins imported from the hosted service, so one response
|
|
66
|
+
# can hold both widths.
|
|
67
|
+
def id_width(plugins) = column_width(plugins.map { |plugin| plugin['id'] }, ID_WIDTH)
|
|
68
|
+
|
|
69
|
+
def column_width(values, minimum) = [*values.map { |value| value.to_s.length }, minimum].max
|
|
70
|
+
|
|
71
|
+
def report_header(text)
|
|
72
|
+
reporter.info " #{text}"
|
|
73
|
+
reporter.info " #{'-' * [text.length, RULE_WIDTH].max}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def description(plugin)
|
|
77
|
+
value = plugin['description'].to_s.strip
|
|
78
|
+
value unless value.empty?
|
|
37
79
|
end
|
|
38
80
|
end
|
|
39
81
|
end
|
data/lib/trmnlp/commands/push.rb
CHANGED
|
@@ -38,11 +38,8 @@ module TRMNLP
|
|
|
38
38
|
raise Aborted, 'aborting' unless %w[y yes].include?(answer)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
zip_file.add(File.basename(file), file)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
41
|
+
removal_requested = !is_new && confirm_server_transform_removal?(api, plugin_settings_id)
|
|
42
|
+
build_archive(removal_requested)
|
|
46
43
|
|
|
47
44
|
response = api.post_plugin_setting_archive(plugin_settings_id, ZIP_PATH)
|
|
48
45
|
paths.plugin_config.write(response.dig('data', 'settings_yaml'))
|
|
@@ -72,6 +69,51 @@ module TRMNLP
|
|
|
72
69
|
ensure
|
|
73
70
|
FileUtils.rm_f(ZIP_PATH)
|
|
74
71
|
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def build_archive(removal_requested)
|
|
76
|
+
Zip::File.open(ZIP_PATH, create: true) do |zip_file|
|
|
77
|
+
paths.src_files.each do |file|
|
|
78
|
+
next if removal_requested && file == paths.plugin_config
|
|
79
|
+
|
|
80
|
+
zip_file.add(File.basename(file), file)
|
|
81
|
+
end
|
|
82
|
+
if removal_requested
|
|
83
|
+
zip_file.get_output_stream('settings.yml') { |entry| entry.write(settings_yaml_with_removal_request) }
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Without this, deleting a local transform.* is a silent no-op: the server
|
|
89
|
+
# keeps executing its copy and every pull re-creates the file. The pushed
|
|
90
|
+
# settings.yml carries `serverless_language: none`, which the importer
|
|
91
|
+
# consumes as an explicit removal request.
|
|
92
|
+
def confirm_server_transform_removal?(api, plugin_settings_id)
|
|
93
|
+
return false if options.force
|
|
94
|
+
return false if paths.transform_file.first
|
|
95
|
+
return false unless server_transform?(api, plugin_settings_id)
|
|
96
|
+
|
|
97
|
+
question = 'The server has a transform script, but this project has no transform file. ' \
|
|
98
|
+
'Delete it on the server too? (y/N) '
|
|
99
|
+
%w[y yes].include?(prompt(question).downcase)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def server_transform?(api, plugin_settings_id)
|
|
103
|
+
archive = api.get_plugin_setting_archive(plugin_settings_id)
|
|
104
|
+
begin
|
|
105
|
+
Zip::File.open(archive.path) { |zip_file| zip_file.any? { |entry| entry.name.start_with?('transform.') } }
|
|
106
|
+
ensure
|
|
107
|
+
archive.close
|
|
108
|
+
end
|
|
109
|
+
rescue Error
|
|
110
|
+
# Advisory check only — an unreadable archive must not block the push.
|
|
111
|
+
false
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def settings_yaml_with_removal_request
|
|
115
|
+
config.plugin.settings.merge('serverless_language' => 'none').to_yaml
|
|
116
|
+
end
|
|
75
117
|
end
|
|
76
118
|
end
|
|
77
119
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../check'
|
|
4
|
+
|
|
5
|
+
module TRMNLP
|
|
6
|
+
module Lint
|
|
7
|
+
module Checks
|
|
8
|
+
# Matches the hosted service's limit. There is no upstream file to sync
|
|
9
|
+
# from, so update this by hand when that limit changes, the same way
|
|
10
|
+
# db/data/form_fields.yml is kept current.
|
|
11
|
+
class DescriptionLength < Check
|
|
12
|
+
MAX_LENGTH = 35
|
|
13
|
+
MESSAGE = "Description should be <= #{MAX_LENGTH} characters long.".freeze
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def pass? = source.plugin_description.length <= MAX_LENGTH
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/trmnlp/lint/source.rb
CHANGED
|
@@ -16,6 +16,7 @@ module TRMNLP
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def plugin_name = settings['name'].to_s
|
|
19
|
+
def plugin_description = settings['description'].to_s
|
|
19
20
|
def settings = config.plugin.settings
|
|
20
21
|
def custom_field_values = config.project.custom_fields
|
|
21
22
|
def custom_field_definitions = config.plugin.custom_field_definitions
|
data/lib/trmnlp/lint.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative 'lint/check'
|
|
|
4
4
|
require_relative 'lint/source'
|
|
5
5
|
require_relative 'lint/checks/title_casing'
|
|
6
6
|
require_relative 'lint/checks/title_length'
|
|
7
|
+
require_relative 'lint/checks/description_length'
|
|
7
8
|
require_relative 'lint/checks/layouts_have_content'
|
|
8
9
|
require_relative 'lint/checks/no_async_functions'
|
|
9
10
|
require_relative 'lint/checks/waits_for_dom_load'
|
|
@@ -23,6 +24,7 @@ module TRMNLP
|
|
|
23
24
|
CHECKS = [
|
|
24
25
|
Checks::TitleCasing,
|
|
25
26
|
Checks::TitleLength,
|
|
27
|
+
Checks::DescriptionLength,
|
|
26
28
|
Checks::LayoutsHaveContent,
|
|
27
29
|
Checks::NoAsyncFunctions,
|
|
28
30
|
Checks::WaitsForDomLoad,
|
data/lib/trmnlp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trmnl_preview
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rockwell Schrock
|
|
@@ -305,6 +305,7 @@ files:
|
|
|
305
305
|
- lib/trmnlp/lint.rb
|
|
306
306
|
- lib/trmnlp/lint/check.rb
|
|
307
307
|
- lib/trmnlp/lint/checks/custom_fields_used.rb
|
|
308
|
+
- lib/trmnlp/lint/checks/description_length.rb
|
|
308
309
|
- lib/trmnlp/lint/checks/form_fields_valid.rb
|
|
309
310
|
- lib/trmnlp/lint/checks/highcharts_animations_disabled.rb
|
|
310
311
|
- lib/trmnlp/lint/checks/highcharts_elements_unique.rb
|