featureparity 0.0.23 → 0.0.24
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/lib/fp/client.rb +4 -2
- data/lib/fp/commands/showroom.rb +2 -0
- data/lib/fp/commands/showroom_media.rb +37 -5
- data/lib/fp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e68b70dce16d28e928ead4413623002ccda97f4508f62bbe6d980c8bb29a21c
|
|
4
|
+
data.tar.gz: e630a9bd6f49db70c343f6374cd3c049a9c9fb4b786251dd313b76a177e0a1f9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 55bde2507b4cfccbe49b8d799d0b3e7efba22c0298450e823a3ac86299ec4d392b0e51f13c3c643a2abc1d60f1d68d091074420c0928fbbcf9da6947fea296d1
|
|
7
|
+
data.tar.gz: c5d9754313a59721bfc78f5d4e65d4924ef1f5120659037cace19e6ee816a96dea0e467f47ad285cf03003ba37ed836501754c5592f9b22385f5a52315be5cae
|
data/lib/fp/client.rb
CHANGED
|
@@ -108,16 +108,17 @@ module Fp
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
# POST /projects/:id/showroom/media/presign
|
|
111
|
-
def presign_showroom_media(project_id, filename:, content_type:, size_bytes:, surface_id: nil)
|
|
111
|
+
def presign_showroom_media(project_id, filename:, content_type:, size_bytes:, surface_id: nil, purpose: nil)
|
|
112
112
|
body = { filename: filename, content_type: content_type, size_bytes: size_bytes }
|
|
113
113
|
body[:surface_id] = surface_id if surface_id
|
|
114
|
+
body[:purpose] = purpose if purpose
|
|
114
115
|
post("/api/projects/#{project_id}/showroom/media/presign", body)
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
# POST /projects/:id/showroom/media
|
|
118
119
|
# Confirm an upload and create the media record.
|
|
119
120
|
def create_showroom_media(project_id, media_id:, s3_key:, filename:, content_type:, size_bytes:,
|
|
120
|
-
surface_id: nil, caption: nil, position: nil)
|
|
121
|
+
surface_id: nil, caption: nil, position: nil, purpose: nil)
|
|
121
122
|
body = {
|
|
122
123
|
media_id: media_id,
|
|
123
124
|
s3_key: s3_key,
|
|
@@ -128,6 +129,7 @@ module Fp
|
|
|
128
129
|
body[:surface_id] = surface_id if surface_id
|
|
129
130
|
body[:caption] = caption if caption
|
|
130
131
|
body[:position] = position if position
|
|
132
|
+
body[:purpose] = purpose if purpose
|
|
131
133
|
post("/api/projects/#{project_id}/showroom/media", body)
|
|
132
134
|
end
|
|
133
135
|
|
data/lib/fp/commands/showroom.rb
CHANGED
|
@@ -23,6 +23,7 @@ module Fp
|
|
|
23
23
|
help_usage 'fp showroom --project <slug>',
|
|
24
24
|
'fp showroom media --project <slug>',
|
|
25
25
|
'fp showroom media add <file> --project <slug> [--surface <key>] [--caption "..."] [--position N]',
|
|
26
|
+
'fp showroom media add <image> --project <slug> --surface <key> --icon',
|
|
26
27
|
'fp showroom media edit <id> --project <slug> [--caption "..."] [--position N]',
|
|
27
28
|
'fp showroom media remove <id> --project <slug> [--yes]'
|
|
28
29
|
help_flag :project, 'Project slug (falls back to .featureparity.yml)'
|
|
@@ -33,6 +34,7 @@ module Fp
|
|
|
33
34
|
help_example 'fp showroom --project stowzilla'
|
|
34
35
|
help_example 'fp showroom media add e2e/checkout.webm --project stowzilla --surface web --caption "Checking out"'
|
|
35
36
|
help_example 'fp showroom media add overview.png --project stowzilla --position 1'
|
|
37
|
+
help_example 'fp showroom media add app-icon.png --project stowzilla --surface ios --icon'
|
|
36
38
|
help_example 'fp showroom media edit <id> --project stowzilla --caption ""'
|
|
37
39
|
help_example 'fp showroom media remove <id> --project stowzilla --yes'
|
|
38
40
|
help_note "Prints the welcome note, the gallery, and each surface's card, then the surfaces that are NOT shown and why.\n" \
|
|
@@ -7,6 +7,7 @@ module Fp
|
|
|
7
7
|
module Commands
|
|
8
8
|
# fp showroom media [--project <slug>] - list the showroom's media
|
|
9
9
|
# fp showroom media add <file> [--surface <key>] [--caption] [--position N]
|
|
10
|
+
# fp showroom media add <image> --surface <key> --icon - set the surface's icon
|
|
10
11
|
# fp showroom media edit <id> [--caption "..."] [--position N]
|
|
11
12
|
# fp showroom media remove <id> [--yes]
|
|
12
13
|
#
|
|
@@ -19,13 +20,19 @@ module Fp
|
|
|
19
20
|
# Uploads reuse attach's flow (presign, PUT the bytes, confirm) and its visual file
|
|
20
21
|
# types — images and videos only. SVG can carry script and PDFs don't render inline,
|
|
21
22
|
# so both are refused before anything is sent.
|
|
23
|
+
#
|
|
24
|
+
# `--icon` (Fizzy #1499) makes the image the surface's own icon in place of the
|
|
25
|
+
# built-in platform logo: one per surface, a new one replaces the old, and removing
|
|
26
|
+
# it brings the built-in logo back.
|
|
22
27
|
class ShowroomMedia < Base
|
|
23
28
|
CONTENT_TYPES = Attach::CONTENT_TYPES.slice(*Attach::VISUAL_EXTENSIONS).freeze
|
|
24
29
|
MAX_FILE_SIZE = Attach::MAX_FILE_SIZE
|
|
25
30
|
MAX_CAPTION_LENGTH = 500
|
|
31
|
+
ICON_EXTENSIONS = %w[png jpg jpeg gif webp].freeze
|
|
32
|
+
MAX_ICON_SIZE = 5 * 1024 * 1024
|
|
26
33
|
|
|
27
34
|
LIST_FLAGS = { project: :string }.freeze
|
|
28
|
-
ADD_FLAGS = { project: :string, surface: :string, caption: :string, position: :string }.freeze
|
|
35
|
+
ADD_FLAGS = { project: :string, surface: :string, caption: :string, position: :string, icon: :boolean }.freeze
|
|
29
36
|
EDIT_FLAGS = { project: :string, caption: :string, position: :string }.freeze
|
|
30
37
|
REMOVE_FLAGS = { project: :string, yes: :boolean }.freeze
|
|
31
38
|
|
|
@@ -83,6 +90,7 @@ module Fp
|
|
|
83
90
|
|
|
84
91
|
# Everything that can be checked locally is checked before a byte is sent.
|
|
85
92
|
file = prepare_file!(path)
|
|
93
|
+
check_icon!(file, opts) if opts[:icon]
|
|
86
94
|
caption = flag_text(opts[:caption]).strip if opts.key?(:caption)
|
|
87
95
|
caption = nil if caption&.empty?
|
|
88
96
|
check_caption!(caption) if caption
|
|
@@ -95,11 +103,12 @@ module Fp
|
|
|
95
103
|
require_project!(opts)
|
|
96
104
|
project_id = resolve_project_id(opts[:project])
|
|
97
105
|
surface = opts[:surface] ? find_surface!(project_id, opts[:surface]) : nil
|
|
106
|
+
purpose = opts[:icon] ? 'icon' : nil
|
|
98
107
|
|
|
99
108
|
presign = fetch!(client.presign_showroom_media(
|
|
100
109
|
project_id,
|
|
101
110
|
filename: file[:filename], content_type: file[:content_type],
|
|
102
|
-
size_bytes: file[:size], surface_id: surface&.dig('id')
|
|
111
|
+
size_bytes: file[:size], surface_id: surface&.dig('id'), purpose: purpose
|
|
103
112
|
), prefix: 'Failed to get upload URL')['presign'] || {}
|
|
104
113
|
|
|
105
114
|
uploaded = client.upload_to_presigned_url(presign['upload_url'], file[:path], file[:content_type])
|
|
@@ -109,13 +118,19 @@ module Fp
|
|
|
109
118
|
project_id,
|
|
110
119
|
media_id: presign['media_id'], s3_key: presign['s3_key'],
|
|
111
120
|
filename: file[:filename], content_type: file[:content_type], size_bytes: file[:size],
|
|
112
|
-
surface_id: surface&.dig('id'), caption: caption, position: position
|
|
121
|
+
surface_id: surface&.dig('id'), caption: caption, position: position, purpose: purpose
|
|
113
122
|
), prefix: 'Failed to confirm upload')['media'] || {}
|
|
114
123
|
|
|
115
124
|
where = surface ? "surface '#{surface['key']}'" : 'the project gallery'
|
|
116
125
|
output.success({ media: item, surface: surface&.dig('key'), project: opts[:project] }) do
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
if purpose
|
|
127
|
+
puts "Set #{file[:filename]} as the icon for #{where} in project '#{opts[:project]}'."
|
|
128
|
+
puts "Remove it to go back to the built-in logo: fp showroom media remove #{item['id']} " \
|
|
129
|
+
"--project #{opts[:project]}"
|
|
130
|
+
else
|
|
131
|
+
puts "Added #{file[:filename]} to #{where} in project '#{opts[:project]}'."
|
|
132
|
+
print_item_detail(item)
|
|
133
|
+
end
|
|
119
134
|
end
|
|
120
135
|
end
|
|
121
136
|
|
|
@@ -239,6 +254,22 @@ module Fp
|
|
|
239
254
|
{ path: path, filename: filename, content_type: content_type, size: size }
|
|
240
255
|
end
|
|
241
256
|
|
|
257
|
+
# An icon is a still picture on one surface, with nothing to caption or order.
|
|
258
|
+
def check_icon!(file, opts)
|
|
259
|
+
problem =
|
|
260
|
+
if flag_text(opts[:surface]).strip.empty? then '--icon needs --surface <key>: an icon belongs to a surface.'
|
|
261
|
+
elsif opts.key?(:caption) || opts.key?(:position) then '--icon takes no --caption or --position.'
|
|
262
|
+
elsif !ICON_EXTENSIONS.include?(File.extname(file[:filename]).delete('.').downcase)
|
|
263
|
+
'An icon must be an image (png, jpg, jpeg, gif, webp).'
|
|
264
|
+
elsif file[:size] > MAX_ICON_SIZE
|
|
265
|
+
"Icon too large: #{format_size(file[:size])} (max #{format_size(MAX_ICON_SIZE)})"
|
|
266
|
+
end
|
|
267
|
+
return unless problem
|
|
268
|
+
|
|
269
|
+
output.error(problem)
|
|
270
|
+
exit 1
|
|
271
|
+
end
|
|
272
|
+
|
|
242
273
|
def check_caption!(caption)
|
|
243
274
|
return if caption.length <= MAX_CAPTION_LENGTH
|
|
244
275
|
|
|
@@ -305,6 +336,7 @@ module Fp
|
|
|
305
336
|
|
|
306
337
|
def print_item_line(item)
|
|
307
338
|
position = item['position'].to_i.positive? ? "##{item['position'].to_i}" : '-'
|
|
339
|
+
position = 'icon' if item['purpose'] == 'icon'
|
|
308
340
|
caption = item['caption'].to_s.strip
|
|
309
341
|
line = " #{item['id']} #{position.ljust(3)} #{item['media_kind'].to_s.ljust(5)} #{item['filename']}"
|
|
310
342
|
line += " \"#{caption}\"" unless caption.empty?
|
data/lib/fp/version.rb
CHANGED