Skip to content

Commit 6e003b4

Browse files
authored
Items: metadata & group management, improve default rendering (openhab#226)
Add the ability to edit metadata from the items details page and the semantic model page: - Provide interactive forms for the alexa, ga, synonyms, widget, listwidget, stateDescription, commandDescription namespaces - Fallback to YAML view for other namespaces (or in a tab for supported namespaces as an alternative). Add "options" widget action to open an action sheet with a list of command options. Add default representation for items: look in the widget for a preconfigured widget (custom or from the standard library), or try to build a default live representation of the item's state (WIP), considering its type, state/command descriptions and other properties. Change the "current state" part of the items details & link edit pages with the default representation. Add a convenient way to add or remove members to/from a group item. Real-time state display to model and thing details pages Add rollershutter system control and card to standard library Add default state representation and metadata editing to the items details pane in the model page Misc fixes, improve mobile-friendliness of model page Harmonize actions below cards, fix homepage hamburger menu Signed-off-by: Yannick Schaus <[email protected]>
1 parent 9130557 commit 6e003b4

37 files changed

+1480
-127
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
2+
const categories = [
3+
'ACTIVITY_TRIGGER',
4+
'CAMERA',
5+
'COMPUTER',
6+
'CONTACT_SENSOR',
7+
'DOOR',
8+
'DOORBELL',
9+
'EXTERIOR_BLIND',
10+
'FAN',
11+
'GAME_CONSOLE',
12+
'GARAGE_DOOR',
13+
'INTERIOR_BLIND',
14+
'LAPTOP',
15+
'LIGHT',
16+
'MICROWAVE',
17+
'MOBILE_PHONE',
18+
'MOTION_SENSOR',
19+
'MUSIC_SYSTEM',
20+
'NETWORK_HARDWARE',
21+
'OTHER',
22+
'OVEN',
23+
'PHONE',
24+
'SCENE_TRIGGER',
25+
'SCREEN',
26+
'SECURITY_PANEL',
27+
'SMARTLOCK',
28+
'SMARTPLUG',
29+
'SPEAKER',
30+
'STREAMING_DEVICE',
31+
'SWITCH',
32+
'TABLET',
33+
'TEMPERATURE_SENSOR',
34+
'THERMOSTAT',
35+
'TV',
36+
'WEARABLE'
37+
]
38+
39+
const labels = {
40+
'Switchable': [],
41+
'Lighting': [],
42+
'Blind': [],
43+
'Door': [],
44+
'Lock': [],
45+
'Outlet': [],
46+
'CurrentHumidity': [],
47+
'CurrentTemperature': [],
48+
'TargetTemperature': [],
49+
'LowerTemperature': [],
50+
'UpperTemperature': [],
51+
'HeatingCoolingMode': [],
52+
'ColorTemperature': [],
53+
'Activity': [],
54+
'Scene': [],
55+
'EntertainmentChannel': [],
56+
'EntertainmentInput': [],
57+
'EqualizerBass': [],
58+
'EqualizerMidrange': [],
59+
'EqualizerTreble': [],
60+
'EqualizerMode': [],
61+
'MediaPlayer': [],
62+
'SpeakerMute': [],
63+
'SpeakerVolume': [],
64+
'ContactSensor': [],
65+
'MotionSensor': [],
66+
'SecurityAlarmMode': [],
67+
'BurglaryAlarm': [],
68+
'FireAlarm': [],
69+
'CarbonMonoxideAlarm': [],
70+
'WaterAlarm': [],
71+
'ModeComponent': [],
72+
'RangeComponent': [],
73+
'ToggleComponent': []
74+
}
75+
76+
const p = (type, name, label, description, options, advanced) => {
77+
return {
78+
name,
79+
type,
80+
label,
81+
description,
82+
advanced,
83+
limitToOptions: !!options,
84+
options: (!options) ? undefined : options.split(',').map((o) => {
85+
const parts = o.split('=')
86+
return { value: parts[0], label: parts[1] || parts[0] }
87+
})
88+
}
89+
}
90+
91+
const categoryParameter = p('TEXT', 'category', 'Category', 'Override the default category for the class', categories.join(','), true)
92+
const scaleParameter = p('TEXT', 'scale', 'Scale', 'Temperature Unit', 'Celsius,Fahrenheit')
93+
const comfortRangeParameter = p('TEXT', 'comfortRange', 'Comfort Range', 'Number to define the comfort range, defaults: 2°F or 1°C')
94+
const setpointRangeParameter = p('TEXT', 'setpointRange', 'Setpoint Range', 'Format: <code>minRange:maxRange</code>')
95+
const rangeParameter = p('TEXT', 'range', 'Range', 'Format: <code>minRange:maxRange</code>')
96+
const volumeIncrementParameter = p('INTEGER', 'increment', 'Increment')
97+
const friendlyNamesParameter = p('TEXT', 'friendlyNames', 'Friendly Names', 'each name formatted as <code>@assetIdOrName</code>, defaults to item label name')
98+
const nonControllableParameter = p('BOOLEAN', 'nonControllable', 'Non Controllable')
99+
const languageParameter = p('TEXT', 'language', 'Language', 'defaults to your server regional settings, if defined, otherwise en', 'de,en,es,fr,hi,it,ja,pt')
100+
const actionMappingsParameter = p('TEXT', 'actionMappings', 'Action Mappings')
101+
const stateMappingsParameter = p('TEXT', 'stateMappings', 'State Mappings')
102+
103+
const capabilities = {
104+
'PowerController.powerState': [],
105+
'BrightnessController.brightness': [],
106+
'PowerLevelController.powerLevel': [],
107+
'PercentageController.percentage': [],
108+
'ThermostatController.targetSetpoint': [
109+
scaleParameter,
110+
setpointRangeParameter
111+
],
112+
'ThermostatController.upperSetpoint': [
113+
scaleParameter,
114+
comfortRangeParameter,
115+
setpointRangeParameter
116+
],
117+
'ThermostatController.lowerSetpoint': [
118+
scaleParameter,
119+
comfortRangeParameter,
120+
setpointRangeParameter
121+
],
122+
'ThermostatController.thermostatMode': [
123+
p('TEXT', 'OFF', 'OFF State'),
124+
p('TEXT', 'HEAT', 'HEAT State'),
125+
p('TEXT', 'COOL', 'COOL State'),
126+
p('TEXT', 'ECO', 'ECO State'),
127+
p('TEXT', 'AUTO', 'AUTO State'),
128+
p('TEXT', 'binding', 'Binding', 'Auto-configure modes for binding', 'daikin,max,nest,zwave'),
129+
p('TEXT', 'supportedModes', 'Supported modes'),
130+
p('BOOLEAN', 'supportsSetpointMode', 'Supports Setpoint Mode', '', null, true)
131+
],
132+
'TemperatureSensor.temperature': [scaleParameter],
133+
'LockController.lockState': [
134+
p('TEXT', 'LOCKED', 'Locked State'),
135+
p('TEXT', 'UNLOCKED', 'Unlocked State'),
136+
p('TEXT', 'JAMMED', 'Jammed State')
137+
],
138+
'ColorController.color': [],
139+
'ColorTemperatureController.colorTemperatureInKelvin': [
140+
p('INTEGER', 'increment', 'Increment'),
141+
rangeParameter,
142+
p('TEXT', 'binding', 'Binding', 'Auto-configure range for binding', 'hue,lifx,milight,tradfri,yeelight')
143+
],
144+
'SceneController.scene': [
145+
p('TEXT', 'supportsDeactivation', 'Supports deactivation')
146+
],
147+
'ChannelController.channel': [
148+
// User should switch to YAML for this one
149+
],
150+
'InputController.input': [
151+
p('TEXT', 'supportedInputs', 'required list of supported input values (e.g. "HMDI1,TV,XBOX")')
152+
],
153+
'Speaker.volume': [
154+
volumeIncrementParameter
155+
],
156+
'Speaker.muted': [],
157+
'StepSpeaker.volume': [
158+
volumeIncrementParameter
159+
],
160+
'StepSpeaker.muted': [],
161+
'PlaybackController.playback': [],
162+
'EqualizerController.bands:bass': [
163+
rangeParameter
164+
],
165+
'EqualizerController.bands:midrange': [
166+
rangeParameter
167+
],
168+
'EqualizerController.bands:treble': [
169+
rangeParameter
170+
],
171+
'EqualizerController.modes': [
172+
p('TEXT', 'MOVIE', 'MOVIE State'),
173+
p('TEXT', 'MUSIC', 'MUSIC State'),
174+
p('TEXT', 'NIGHT', 'NIGHT State'),
175+
p('TEXT', 'SPORT', 'SPORT State'),
176+
p('TEXT', 'TV', 'TV State'),
177+
p('TEXT', 'supportedModes', 'Supported modes')
178+
],
179+
180+
// TODO the rest
181+
'ContactSensor.detectionState': [],
182+
'MotionSensor.detectionState': [],
183+
'SecurityPanelController.armState': [
184+
p('TEXT', 'DISARMED', 'DISARMED State'),
185+
p('TEXT', 'ARMED_STAY', 'ARMED_STAY State'),
186+
p('TEXT', 'ARMED_AWAY', 'ARMED_AWAY State'),
187+
p('TEXT', 'ARMED_NIGHT', 'ARMED_NIGHT State'),
188+
p('TEXT', 'AUTHORIZATION_REQUIRED', 'AUTHORIZATION_REQUIRED State'),
189+
p('TEXT', 'UNAUTHORIZED', 'UNAUTHORIZED State'),
190+
p('TEXT', 'NOT_READY', 'NOT_READY State'),
191+
p('TEXT', 'UNCLEARED_ALARM', 'UNCLEARED_ALARM State'),
192+
p('TEXT', 'UNCLEARED_TROUBLE', 'UNCLEARED_TROUBLE State'),
193+
p('TEXT', 'BYPASS_NEEDED', 'BYPASS_NEEDED State'),
194+
p('TEXT', 'supportedArmStates', 'Supported arm states'),
195+
p('BOOLEAN', 'supportsPinCodes', 'Supports pin codes'),
196+
p('INTEGER', 'exitDelay', 'Exit Delay')
197+
],
198+
'SecurityPanelController.burglaryAlarm': [],
199+
'SecurityPanelController.fireAlarm': [],
200+
'SecurityPanelController.carbonMonoxideAlarm': [],
201+
'SecurityPanelController.waterAlarm': [],
202+
'ModeController.mode': [
203+
friendlyNamesParameter,
204+
nonControllableParameter,
205+
p('TEXT', 'supportedModes', 'Supported Modes'),
206+
p('BOOLEAN', 'ordered', 'Ordered'),
207+
languageParameter,
208+
actionMappingsParameter,
209+
stateMappingsParameter
210+
],
211+
'RangeController.rangeValue': [
212+
friendlyNamesParameter,
213+
nonControllableParameter,
214+
p('TEXT', 'supportedRange', 'Supported Range'),
215+
p('TEXT', 'presets', 'Presets'),
216+
p('TEXT', 'unitOfMeasure', 'Unit of Measure'),
217+
languageParameter,
218+
actionMappingsParameter,
219+
stateMappingsParameter
220+
],
221+
'ToggleController.toggleState': [
222+
friendlyNamesParameter,
223+
nonControllableParameter,
224+
languageParameter,
225+
actionMappingsParameter,
226+
stateMappingsParameter
227+
]
228+
}
229+
230+
let classes = {}
231+
232+
for (let l in labels) {
233+
labels[l].unshift(categoryParameter)
234+
classes['label:' + l] = labels[l]
235+
}
236+
237+
for (let c in capabilities) {
238+
capabilities[c].unshift(categoryParameter)
239+
classes[c] = capabilities[c]
240+
}
241+
242+
export default classes
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
const p = (type, name, label, description, options, advanced) => {
2+
return {
3+
name,
4+
type,
5+
label,
6+
description,
7+
advanced,
8+
limitToOptions: !!options,
9+
options: (!options) ? undefined : options.split(',').map((o) => {
10+
const parts = o.split('=')
11+
return { value: parts[0], label: parts[1] || parts[0] }
12+
})
13+
}
14+
}
15+
16+
const tfaAckParameter = p('BOOLEAN', 'tfaAck', 'TFA Ack Needed')
17+
const tfaPinParameter = p('TEXT', 'tfaPin', 'TFA Pin')
18+
const nameParameter = p('TEXT', 'name', 'Name', 'Custom name (use of the synonyms is preferred)', null, true)
19+
const roomHintParameter = p('TEXT', 'roomHint', 'Room Hint', null, null, true)
20+
const invertedParameter = p('BOOLEAN', 'inverted', 'Inverted')
21+
const speedParameter = p('TEXT', 'speed', 'Speed', 'Mappings between items states and Google modes')
22+
const orderedParameter = p('BOOLEAN', 'ordered', 'Ordered')
23+
const useFahrenheitParameter = p('BOOLEAN', 'useFahrenheit', 'Use Fahrenheit')
24+
const thermostatModesParameter = p('TEXT', 'modes', 'Thermostat Modes', 'Mappings between items states and Google modes')
25+
26+
const classes = {
27+
'Light': [],
28+
'Switch': [],
29+
'Outlet': [],
30+
'CoffeeMaker': [],
31+
'WaterHeater': [],
32+
'Fireplace': [],
33+
'Valve': [],
34+
'Sprinkler': [],
35+
'Vacuum': [],
36+
'Scene': [],
37+
'Lock': [],
38+
'SecuritySystem': [],
39+
'Speaker': [],
40+
'Fan': [ speedParameter, orderedParameter ],
41+
'Hood': [ speedParameter, orderedParameter ],
42+
'AirPurifier': [ speedParameter, orderedParameter ],
43+
'Awning': [ invertedParameter ],
44+
'Blinds': [ invertedParameter ],
45+
'Curtain': [ invertedParameter ],
46+
'Door': [ invertedParameter ],
47+
'Garage': [ invertedParameter ],
48+
'Gate': [ invertedParameter ],
49+
'Pergola': [ invertedParameter ],
50+
'Shutter': [ invertedParameter ],
51+
'Window': [ invertedParameter ],
52+
'Thermostat': [ useFahrenheitParameter, thermostatModesParameter ],
53+
'thermostatTemperatureAmbient': [],
54+
'thermostatHumidityAmbient': [],
55+
'thermostatTemperatureSetpoint': [],
56+
'thermostatMode': [],
57+
'Camera': []
58+
}
59+
60+
for (let c in classes) {
61+
classes[c] = [...classes[c], tfaAckParameter, tfaPinParameter, nameParameter, roomHintParameter]
62+
}
63+
64+
export default classes
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export default [
2+
{ name: 'stateDescription', label: 'State Description' },
3+
{ name: 'commandDescription', label: 'Command Options' },
4+
{ name: 'synonyms', label: 'Synonyms' },
5+
{ name: 'widget', label: 'Default Standalone Widget' },
6+
{ name: 'listWidget', label: 'Default List Item Widget' },
7+
{ name: 'autoupdate', label: 'Auto-update' },
8+
{ name: 'alexa', label: 'Amazon Alexa' },
9+
{ name: 'ga', label: 'Google Assistant' }
10+
]

bundles/org.openhab.ui/web/src/components/app.vue

+8
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,15 @@
150150
</template>
151151

152152
<style lang="stylus" scoped>
153+
.panel-left::-webkit-scrollbar /* WebKit */
154+
width 0
155+
height 0
156+
153157
.panel-left
158+
overflow-y scroll
159+
scrollbar-width none /* Firefox */
160+
-ms-overflow-style none /* IE 10+ */
161+
154162
.page
155163
background #f5f5f5 !important
156164
padding-bottom 4rem

0 commit comments

Comments
 (0)