Repository navigation
Description
- one generic component that is configured declaratively (same declarative language that will be used to power review bot validation and index dimensions)
- presentation is not part of declarative definition (e.g. instead through curated
::slotted(<...>)styling,"id"property uniquely identifies type of input) - same component for displaying and editing that progressively enhances with editing capabilities
- selection options can either be defined statically, or as a reference to a resource that is fetched dynamically (e.g. brand / device / category)
- static selection options can specify icon names out of defined icon-set
- enforces same validation rules as review bot
- should be
<form>compatible
declarative language snippets can be considered a proposal and should be changed if there ends up being a better way to express a concept
options sourcing endpoints for dynamic selection will use the same pagination pattern used by /api/unstable/derives/devices and others (link header is rfc8288 style resource navigation with "next" / "prev" / "last" / "first" relations, content-range encodes collection cardinality with items unit)
?term query parameter being used for filtering
endpoints will take a while to become available, mock data is fine for now
a way to be able to play with the component more easily would be neat
one option is a temporary page that displays the component itself and a text field to customize the definition, but other approaches are fine as well if they serve the same goal
including translations as part of the definition would be beneficial for other consumers of definition (the review bot and server)
how this can be wired up into localize is still up for discussion
{
"id": "name",
"type": "text",
"label": {"en": "Name"},
"hint": {"en": "Name of the device"},
"description": {"en": "Minimally identifying name of a device."},
"pattern": {
"multiline": false,
// enables nicer validation hints than enforcement through regex
"length": {
"max": 64,
"min": 3
},
// validate character by character
// combined to anchored regex to determine if erroneous
// ran character by character on error to reveal invalid character position in validation hint
"kind": "letter",
"regex": "[\\\\p{L}\\\\p{M}\\\\p{N}\\\\p{P}\\\\p{Zs}\\\\p{Sc}\\\\p{Sm}]"
}
}device name trait input
{
"id": "light.dimming",
"type": "toggle",
"label": {"en": "Dimmable"},
"hint": {"en": "Capable of brightness adjustments"},
"description": {"en": "Indicates that the device has brightness adjustment capability."},
}dimmable trait toggle
was redefined as "radio" after initial discussion because it has three states (yes / no / not set)
went back to "toggle" as radio implies a customizable selection and different styling
{
"id": "ean",
"type": "text",
"label": {"en": "EAN"},
"hint": {"en": "A European barcode"},
"description": {"en": "An EAN-13 or EAN-8 barcode."},
"pattern": {
"multiline": false,
// regular expressions are not capable of validating EANs
"kind": "ean"
}
}a ean-style barcode input
included to illustrate validation rules that can't be be sufficiently expressed with regular expressions
{
"id": "brand",
"type": "picker",
"label": {"en": "Brand"},
"resource": "brand",
"hint": {"en": "Vendor that put their brand on the device"},
"description": {"en": "The vendor that put their brand on a device. Often the manufacturer of a device, but not necessarily."},
}brand picker
preliminary structure of endpoint response:
[
{"name": "<brand-name>", "count": <count>},
...
]
{
"id": "category",
"type": "picker",
"label": {"en": "Category"},
"resource": "category",
"hint": {"en": "Category of the device"},
"description": {"en": "Primary category of a device"},
}category picker
preliminary structure of endpoint response:
[
{"name": "<category-name>", "count": <count>},
...
]
{
"id": "local-operation",
"type": "picker",
"label": {"en": "Local Operation"},
"resource": "none",
"options": [
{
"id": "local",
"title": {"en": "Fully Local"},
"subtitle": {"en": "Does not depend on cloud access for any functionality."},
// e.g. ☀️
"icon": "sun",
},
{
"id": "cloud-ish",
"title": {"en": "Degraded without Cloud"},
"subtitle": {"en": "Needs cloud access for full functionality."},
// e.g. ⛅
"icon": "sun-behind-cloud",
}
{
"id": "cloud",
"title": {"en": "Cloud Required"},
"subtitle": {"en": "Can not be used without cloud access."},
// e.g. ☁️
"icon": "️cloud",
}
],
"hint": {"en": "Local operation"},
"description": {"en": "Primary category of a device."},
}local operation picker
{
"id": "photos",
"type": "photos",
"label": {"en": "Photos"},
"categories": {
"packshot": {
"label": {"en": "Packshot"},
"description": {"en": "Clean, isolated product on a plain background."},
},
"hero-shot": {
"label": {"en": "Hero shot"},
"description": {"en": "Visually striking composition showcasing the product as the main focus."},
},
"packaging": {
"label": {"en": "Packaging"},
"description": {"en": "The product’s packaging, including its design, labels, and materials."},
},
"unboxing": {
"label": {"en": "Unboxing"},
"description": {"en": "The product being removed from or revealed inside its packaging."},
},
"product-in-use": {
"label": {"en": "Product-in-use"},
"description": {"en": "The product being used in a real-life context."},
},
},
"pattern": {
"slots": [
{
"constrained": true,
// can be either
"categories": ["packshot", "hero-shot"],
},
{
"constrained": true,
"constrained": ["product-in-use"]
},
{
"constrained": true,
"constrained": ["unboxing"]
},
{
"constrained": true,
"categories": ["packaging"],
},
{
"constrained": false
},
{
"constrained": false
},
]
}
}Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity