@seamapi/react 1.64.0 → 2.0.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.
- package/README.md +16 -4
- package/dist/elements.js +5533 -5359
- package/dist/elements.js.map +1 -1
- package/dist/index.css +17 -19
- package/dist/index.css.map +1 -1
- package/dist/index.min.css +1 -1
- package/dist/index.min.css.map +1 -1
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.d.ts +1 -1
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js +11 -13
- package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.d.ts +4 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js +3 -2
- package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js.map +1 -1
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.d.ts +1 -5
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +15 -11
- package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
- package/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.d.ts +1 -1
- package/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js +2 -2
- package/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js.map +1 -1
- package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.d.ts +1 -1
- package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js +12 -7
- package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js.map +1 -1
- package/lib/seam/components/DeviceDetails/LockDeviceDetails.js +11 -4
- package/lib/seam/components/DeviceDetails/LockDeviceDetails.js.map +1 -1
- package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.d.ts +1 -1
- package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js +4 -4
- package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js.map +1 -1
- package/lib/seam/components/DeviceTable/DeviceHealthBar.d.ts +3 -1
- package/lib/seam/components/DeviceTable/DeviceHealthBar.js +4 -3
- package/lib/seam/components/DeviceTable/DeviceHealthBar.js.map +1 -1
- package/lib/seam/components/DeviceTable/DeviceTable.d.ts +1 -5
- package/lib/seam/components/DeviceTable/DeviceTable.js +14 -9
- package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.d.ts +3 -3
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js +11 -17
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.d.ts +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.js +1 -7
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +3 -3
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js +12 -31
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.d.ts +2 -2
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.js +2 -4
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceManufacturerSection.d.ts +8 -0
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceManufacturerSection.js +35 -0
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceManufacturerSection.js.map +1 -0
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.d.ts +2 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js +10 -6
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.d.ts +3 -7
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js +4 -5
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/use-device-model.d.ts +7 -0
- package/lib/seam/components/SupportedDeviceTable/use-device-model.js +18 -0
- package/lib/seam/components/SupportedDeviceTable/use-device-model.js.map +1 -0
- package/lib/seam/components/SupportedDeviceTable/use-device-models.d.ts +7 -0
- package/lib/seam/components/SupportedDeviceTable/use-device-models.js +17 -0
- package/lib/seam/components/SupportedDeviceTable/use-device-models.js.map +1 -0
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.d.ts +5 -5
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js +16 -17
- package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js.map +1 -1
- package/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.d.ts +8 -0
- package/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.js +37 -0
- package/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.js.map +1 -0
- package/lib/seam/components/SupportedDeviceTable/use-manufacturer.d.ts +7 -0
- package/lib/seam/components/SupportedDeviceTable/use-manufacturer.js +18 -0
- package/lib/seam/components/SupportedDeviceTable/use-manufacturer.js.map +1 -0
- package/lib/seam/components/SupportedDeviceTable/use-manufacturers.d.ts +7 -0
- package/lib/seam/components/SupportedDeviceTable/use-manufacturers.js +17 -0
- package/lib/seam/components/SupportedDeviceTable/use-manufacturers.js.map +1 -0
- package/lib/seam/components/common-props.d.ts +3 -0
- package/lib/seam/components/common-props.js.map +1 -1
- package/lib/seam/filters.d.ts +8 -0
- package/lib/seam/filters.js +16 -0
- package/lib/seam/filters.js.map +1 -0
- package/lib/telemetry/client.js.map +1 -1
- package/lib/ui/Snackbar/Snackbar.d.ts +1 -1
- package/lib/ui/Snackbar/Snackbar.js +1 -1
- package/lib/ui/Snackbar/Snackbar.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +14 -4
- package/src/lib/element.tsx +2 -0
- package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +24 -30
- package/src/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.tsx +9 -1
- package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +34 -13
- package/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.tsx +4 -0
- package/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.tsx +21 -5
- package/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +19 -8
- package/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx +6 -2
- package/src/lib/seam/components/DeviceTable/DeviceHealthBar.tsx +10 -2
- package/src/lib/seam/components/DeviceTable/DeviceTable.tsx +31 -15
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.tsx +23 -29
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.tsx +3 -9
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.tsx +22 -41
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.tsx +8 -12
- package/src/lib/seam/components/SupportedDeviceTable/{SupportedDeviceBrandSection.tsx → SupportedDeviceManufacturerSection.tsx} +19 -26
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.tsx +20 -11
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.element.ts +2 -3
- package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.tsx +10 -17
- package/src/lib/seam/components/SupportedDeviceTable/use-device-model.ts +45 -0
- package/src/lib/seam/components/SupportedDeviceTable/use-device-models.ts +43 -0
- package/src/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.ts +31 -20
- package/src/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.ts +54 -0
- package/src/lib/seam/components/SupportedDeviceTable/use-manufacturer.ts +45 -0
- package/src/lib/seam/components/SupportedDeviceTable/use-manufacturers.ts +43 -0
- package/src/lib/seam/components/common-props.tsx +10 -0
- package/src/lib/seam/filters.ts +32 -0
- package/src/lib/telemetry/client.ts +3 -3
- package/src/lib/ui/Snackbar/Snackbar.tsx +2 -2
- package/src/lib/version.ts +1 -1
- package/src/styles/_device-details.scss +1 -2
- package/src/styles/_supported-device-table.scss +4 -4
- package/src/styles/_thermostat.scss +1 -2
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceBrandSection.d.ts +0 -8
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceBrandSection.js +0 -42
- package/lib/seam/components/SupportedDeviceTable/SupportedDeviceBrandSection.js.map +0 -1
- package/lib/seam/components/SupportedDeviceTable/use-device-provider.d.ts +0 -2
- package/lib/seam/components/SupportedDeviceTable/use-device-provider.js +0 -13
- package/lib/seam/components/SupportedDeviceTable/use-device-provider.js.map +0 -1
- package/lib/seam/device-models/use-device-models.d.ts +0 -5
- package/lib/seam/device-models/use-device-models.js +0 -19
- package/lib/seam/device-models/use-device-models.js.map +0 -1
- package/lib/strings.d.ts +0 -1
- package/lib/strings.js +0 -4
- package/lib/strings.js.map +0 -1
- package/src/lib/seam/components/SupportedDeviceTable/use-device-provider.ts +0 -16
- package/src/lib/seam/device-models/use-device-models.ts +0 -39
- package/src/lib/strings.ts +0 -3
|
@@ -2,19 +2,19 @@ import type { Dispatch, SetStateAction } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { FilterCategoryMenu } from 'lib/seam/components/SupportedDeviceTable/FilterCategoryMenu.js'
|
|
4
4
|
import type { DeviceModelFilters } from 'lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js'
|
|
5
|
-
import { useDeviceModels } from 'lib/seam/device-models/use-device-models.js'
|
|
6
|
-
import { capitalize } from 'lib/strings.js'
|
|
7
5
|
import { Button } from 'lib/ui/Button.js'
|
|
8
6
|
import { Menu } from 'lib/ui/Menu/Menu.js'
|
|
9
7
|
import { SearchTextField } from 'lib/ui/TextField/SearchTextField.js'
|
|
10
8
|
|
|
9
|
+
import { useFilteredManufacturers } from './use-filtered-manufacturers.js'
|
|
10
|
+
|
|
11
11
|
interface SupportedDeviceFilterAreaProps {
|
|
12
12
|
filterValue: string
|
|
13
13
|
setFilterValue: (filter: string) => void
|
|
14
14
|
filters: DeviceModelFilters
|
|
15
15
|
setFilters: Dispatch<SetStateAction<DeviceModelFilters>>
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
manufacturers: string[] | null
|
|
17
|
+
excludedManufacturers: string[]
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export function SupportedDeviceFilterArea({
|
|
@@ -22,12 +22,15 @@ export function SupportedDeviceFilterArea({
|
|
|
22
22
|
setFilterValue,
|
|
23
23
|
filters,
|
|
24
24
|
setFilters,
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
manufacturers,
|
|
26
|
+
excludedManufacturers,
|
|
27
27
|
}: SupportedDeviceFilterAreaProps): JSX.Element {
|
|
28
28
|
const appliedFiltersCount = getAppliedFilterCount(filters)
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const { manufacturers: availableManufacturers } = useFilteredManufacturers({
|
|
31
|
+
manufacturers,
|
|
32
|
+
excludedManufacturers,
|
|
33
|
+
})
|
|
31
34
|
|
|
32
35
|
const resetFilter = (filterType: keyof DeviceModelFilters): void => {
|
|
33
36
|
setFilters((filters) => ({
|
|
@@ -64,18 +67,22 @@ export function SupportedDeviceFilterArea({
|
|
|
64
67
|
>
|
|
65
68
|
<div className='seam-filter-menu-row'>
|
|
66
69
|
<FilterCategoryMenu
|
|
67
|
-
label={t.
|
|
70
|
+
label={t.manufacturer}
|
|
68
71
|
allLabel={allLabel}
|
|
69
|
-
options={
|
|
70
|
-
|
|
72
|
+
options={
|
|
73
|
+
availableManufacturers?.map(
|
|
74
|
+
(manufacturer) => manufacturer.display_name
|
|
75
|
+
) ?? []
|
|
76
|
+
}
|
|
77
|
+
onSelect={(manufacturer: string) => {
|
|
71
78
|
setFilters((filters) => ({
|
|
72
79
|
...filters,
|
|
73
|
-
|
|
80
|
+
manufacturer,
|
|
74
81
|
}))
|
|
75
82
|
}}
|
|
76
|
-
buttonLabel={filters.
|
|
83
|
+
buttonLabel={filters.manufacturer ?? allLabel}
|
|
77
84
|
onAllOptionSelect={() => {
|
|
78
|
-
resetFilter('
|
|
85
|
+
resetFilter('manufacturer')
|
|
79
86
|
}}
|
|
80
87
|
/>
|
|
81
88
|
</div>
|
|
@@ -118,40 +125,14 @@ export function SupportedDeviceFilterArea({
|
|
|
118
125
|
|
|
119
126
|
const getAppliedFilterCount = (filters: DeviceModelFilters): number => {
|
|
120
127
|
let count = 0
|
|
121
|
-
if (filters.
|
|
128
|
+
if (filters.manufacturer !== null) count++
|
|
122
129
|
if (!filters.supportedOnly) count++
|
|
123
130
|
return count
|
|
124
131
|
}
|
|
125
132
|
|
|
126
|
-
const useAvailableBrands = (
|
|
127
|
-
brands: string[] | null,
|
|
128
|
-
excludedBrands: string[]
|
|
129
|
-
): string[] => {
|
|
130
|
-
const { deviceModels } = useDeviceModels()
|
|
131
|
-
|
|
132
|
-
if (deviceModels == null) return []
|
|
133
|
-
|
|
134
|
-
const availableBrands = deviceModels
|
|
135
|
-
.map(({ brand }) => brand.trim())
|
|
136
|
-
.filter((brand) => {
|
|
137
|
-
// UPSTREAM: API can return an empty value for brand.
|
|
138
|
-
return brand !== ''
|
|
139
|
-
})
|
|
140
|
-
.filter((brand) => {
|
|
141
|
-
if (brands === null) return true
|
|
142
|
-
return brands.includes(brand)
|
|
143
|
-
})
|
|
144
|
-
.filter((brand) => {
|
|
145
|
-
return !excludedBrands.includes(brand)
|
|
146
|
-
})
|
|
147
|
-
.map((brand) => capitalize(brand))
|
|
148
|
-
|
|
149
|
-
return Array.from(new Set(availableBrands))
|
|
150
|
-
}
|
|
151
|
-
|
|
152
133
|
const t = {
|
|
153
134
|
all: 'All',
|
|
154
|
-
|
|
135
|
+
manufacturer: 'Manufacturer',
|
|
155
136
|
supported: 'Supported',
|
|
156
137
|
filter: 'Filter',
|
|
157
138
|
filters: 'Filters',
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DeviceModelV1 } from '@seamapi/types/devicedb'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
connectionTypeNames,
|
|
5
4
|
ImageColumn,
|
|
6
5
|
StatusColumn,
|
|
7
6
|
} from 'lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js'
|
|
8
|
-
import { useDeviceProvider } from 'lib/seam/components/SupportedDeviceTable/use-device-provider.js'
|
|
9
7
|
import { DotDivider } from 'lib/ui/layout/DotDivider.js'
|
|
10
8
|
|
|
11
9
|
interface SupportedDeviceFilterResultRowProps {
|
|
12
|
-
deviceModel:
|
|
10
|
+
deviceModel: DeviceModelV1
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
export function SupportedDeviceFilterResultRow({
|
|
@@ -27,23 +25,21 @@ export function SupportedDeviceFilterResultRow({
|
|
|
27
25
|
export function ModelColumn({
|
|
28
26
|
deviceModel,
|
|
29
27
|
}: SupportedDeviceFilterResultRowProps): JSX.Element {
|
|
30
|
-
const deviceProvider = useDeviceProvider(deviceModel.brand)
|
|
31
|
-
|
|
32
28
|
return (
|
|
33
29
|
<div className='seam-col seam-model-col'>
|
|
34
30
|
<div className='seam-model-name'>
|
|
35
31
|
<img
|
|
36
|
-
src={
|
|
37
|
-
alt={deviceModel.
|
|
38
|
-
className='seam-
|
|
32
|
+
src={deviceModel.manufacturer.logo?.url}
|
|
33
|
+
alt={deviceModel.manufacturer.display_name}
|
|
34
|
+
className='seam-manufacturer-image'
|
|
39
35
|
/>{' '}
|
|
40
|
-
<div className='seam-truncated-text'>{deviceModel.
|
|
36
|
+
<div className='seam-truncated-text'>{deviceModel.display_name}</div>
|
|
41
37
|
</div>
|
|
42
38
|
<div className='seam-model-id'>
|
|
43
39
|
<div className='seam-truncated-text'>
|
|
44
|
-
{deviceModel.
|
|
40
|
+
{deviceModel.device_model_id}
|
|
45
41
|
<DotDivider />
|
|
46
|
-
{
|
|
42
|
+
{deviceModel.main_connection_type}
|
|
47
43
|
</div>
|
|
48
44
|
</div>
|
|
49
45
|
</div>
|
|
@@ -1,30 +1,29 @@
|
|
|
1
|
+
import type { DeviceModelV1 } from '@seamapi/types/devicedb'
|
|
1
2
|
import classNames from 'classnames'
|
|
2
|
-
import type { DeviceModel } from 'seamapi'
|
|
3
3
|
|
|
4
4
|
import { ChevronRightIcon } from 'lib/icons/ChevronRight.js'
|
|
5
5
|
import { HiddenDevicesOverlay } from 'lib/seam/components/SupportedDeviceTable/HiddenDevicesOverlay.js'
|
|
6
6
|
import { ShowAllDevicesButton } from 'lib/seam/components/SupportedDeviceTable/ShowAllDevicesButton.js'
|
|
7
7
|
import { SupportedDeviceRow } from 'lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js'
|
|
8
|
-
import {
|
|
8
|
+
import { useManufacturer } from 'lib/seam/components/SupportedDeviceTable/use-manufacturer.js'
|
|
9
9
|
import { useToggle } from 'lib/ui/use-toggle.js'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* How many device models required before
|
|
13
|
-
*
|
|
14
|
-
* view all.
|
|
12
|
+
* How many device models required before collapsing the list,
|
|
13
|
+
* and requiring the user to click to view all.
|
|
15
14
|
*/
|
|
16
15
|
const maxDevicesBeforeCollapsing = 3
|
|
17
16
|
|
|
18
|
-
interface
|
|
19
|
-
|
|
20
|
-
deviceModels:
|
|
17
|
+
interface SupportedDeviceManufacturerSectionProps {
|
|
18
|
+
manufacturerId: string
|
|
19
|
+
deviceModels: DeviceModelV1[]
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
export function
|
|
24
|
-
|
|
22
|
+
export function SupportedDeviceManufacturerSection({
|
|
23
|
+
manufacturerId,
|
|
25
24
|
deviceModels,
|
|
26
|
-
}:
|
|
27
|
-
const
|
|
25
|
+
}: SupportedDeviceManufacturerSectionProps): JSX.Element | null {
|
|
26
|
+
const { manufacturer } = useManufacturer({ manufacturer_id: manufacturerId })
|
|
28
27
|
|
|
29
28
|
const [expanded, toggleExpand] = useToggle()
|
|
30
29
|
|
|
@@ -47,32 +46,26 @@ export function SupportedDeviceBrandSection({
|
|
|
47
46
|
|
|
48
47
|
return (
|
|
49
48
|
<div
|
|
50
|
-
className={classNames('seam-
|
|
49
|
+
className={classNames('seam-manufacturer-section', {
|
|
51
50
|
'can-expand': canExpand,
|
|
52
51
|
expanded,
|
|
53
52
|
})}
|
|
54
53
|
>
|
|
55
54
|
<div className='seam-header' onClick={handleHeaderClick}>
|
|
56
55
|
<img
|
|
57
|
-
src={
|
|
58
|
-
alt={
|
|
59
|
-
className='seam-
|
|
56
|
+
src={manufacturer?.logo?.url}
|
|
57
|
+
alt={manufacturer?.display_name}
|
|
58
|
+
className='seam-manufacturer-image'
|
|
60
59
|
/>
|
|
61
|
-
<h5 className='seam-
|
|
62
|
-
{
|
|
60
|
+
<h5 className='seam-manufacturer-name'>
|
|
61
|
+
{manufacturer?.display_name} {t.devices}
|
|
63
62
|
</h5>
|
|
64
63
|
{canExpand && <ChevronRightIcon className='chevron' />}
|
|
65
64
|
</div>
|
|
66
65
|
<div className='seam-supported-device-table-content'>
|
|
67
|
-
{visibleDevices.map((deviceModel
|
|
66
|
+
{visibleDevices.map((deviceModel) => (
|
|
68
67
|
<SupportedDeviceRow
|
|
69
|
-
key={
|
|
70
|
-
deviceModel.main_category,
|
|
71
|
-
deviceModel.brand,
|
|
72
|
-
deviceModel.model_name,
|
|
73
|
-
deviceModel.manufacturer_model_id,
|
|
74
|
-
index,
|
|
75
|
-
].join(':')}
|
|
68
|
+
key={deviceModel.device_model_id}
|
|
76
69
|
deviceModel={deviceModel}
|
|
77
70
|
/>
|
|
78
71
|
))}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import type { DeviceModelV1 } from '@seamapi/types/devicedb'
|
|
1
2
|
import classNames from 'classnames'
|
|
2
3
|
import type { DeviceModel } from 'seamapi'
|
|
3
4
|
|
|
4
5
|
import { DotDivider } from 'lib/ui/layout/DotDivider.js'
|
|
5
6
|
|
|
6
7
|
interface SupportedDeviceRowProps {
|
|
7
|
-
deviceModel:
|
|
8
|
+
deviceModel: DeviceModelV1
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export function SupportedDeviceRow({
|
|
@@ -25,7 +26,10 @@ export function ImageColumn({
|
|
|
25
26
|
return (
|
|
26
27
|
<div className='seam-col seam-device-image-col'>
|
|
27
28
|
<div className='seam-image-box'>
|
|
28
|
-
<img
|
|
29
|
+
<img
|
|
30
|
+
width={40}
|
|
31
|
+
src={deviceModel.aesthetic_variants[0]?.images[0]?.url}
|
|
32
|
+
/>
|
|
29
33
|
</div>
|
|
30
34
|
</div>
|
|
31
35
|
)
|
|
@@ -37,13 +41,13 @@ export function ModelColumn({
|
|
|
37
41
|
return (
|
|
38
42
|
<div className='seam-col seam-model-col'>
|
|
39
43
|
<div className='seam-model-name'>
|
|
40
|
-
<div className='seam-truncated-text'>{deviceModel.
|
|
44
|
+
<div className='seam-truncated-text'>{deviceModel.display_name}</div>
|
|
41
45
|
</div>
|
|
42
46
|
<div className='seam-model-id'>
|
|
43
47
|
<div className='seam-truncated-text'>
|
|
44
|
-
{deviceModel.
|
|
48
|
+
{deviceModel.device_model_id}
|
|
45
49
|
<DotDivider />
|
|
46
|
-
{
|
|
50
|
+
{deviceModel.main_connection_type}
|
|
47
51
|
</div>
|
|
48
52
|
</div>
|
|
49
53
|
</div>
|
|
@@ -53,30 +57,35 @@ export function ModelColumn({
|
|
|
53
57
|
export function StatusColumn({
|
|
54
58
|
deviceModel,
|
|
55
59
|
}: SupportedDeviceRowProps): JSX.Element {
|
|
56
|
-
const statusColor =
|
|
60
|
+
const statusColor =
|
|
61
|
+
supportLevelColors[deviceModel.manufacturer.integration] ?? 'unknown'
|
|
57
62
|
|
|
58
63
|
return (
|
|
59
64
|
<div className='seam-col seam-status-col'>
|
|
60
65
|
<div className={classNames('seam-status-pill', `status-${statusColor}`)}>
|
|
61
|
-
<span>{status[deviceModel.
|
|
66
|
+
<span>{status[deviceModel.manufacturer.integration]}</span>
|
|
62
67
|
</div>
|
|
63
68
|
</div>
|
|
64
69
|
)
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
const supportLevelColors: Record<
|
|
68
|
-
|
|
73
|
+
DeviceModelV1['manufacturer']['integration'],
|
|
69
74
|
'green' | 'blue' | 'unknown'
|
|
70
75
|
> = {
|
|
71
|
-
|
|
76
|
+
stable: 'green',
|
|
72
77
|
beta: 'blue',
|
|
78
|
+
planned: 'unknown',
|
|
73
79
|
unsupported: 'unknown',
|
|
80
|
+
inquire: 'unknown',
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
const status: Record<
|
|
77
|
-
|
|
83
|
+
const status: Record<DeviceModelV1['manufacturer']['integration'], string> = {
|
|
84
|
+
stable: 'LIVE',
|
|
78
85
|
beta: 'BETA',
|
|
79
86
|
unsupported: 'Inquire',
|
|
87
|
+
planned: 'Inquire',
|
|
88
|
+
inquire: 'Inquire',
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
export const connectionTypeNames: Record<
|
|
@@ -5,10 +5,9 @@ import type { SupportedDeviceTableProps } from './SupportedDeviceTable.js'
|
|
|
5
5
|
export const name = 'seam-supported-device-table'
|
|
6
6
|
|
|
7
7
|
export const props: ElementProps<SupportedDeviceTableProps> = {
|
|
8
|
-
cannotFilter: 'boolean',
|
|
9
8
|
disableFilter: 'boolean',
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
manufacturers: 'array',
|
|
10
|
+
excludedManufacturers: 'array',
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
export { SupportedDeviceTable as Component } from './SupportedDeviceTable.js'
|
|
@@ -13,12 +13,8 @@ import type { DeviceModelFilters } from 'lib/seam/components/SupportedDeviceTabl
|
|
|
13
13
|
|
|
14
14
|
export interface SupportedDeviceTableProps extends CommonProps {
|
|
15
15
|
disableFilter?: boolean
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
19
|
-
cannotFilter?: boolean
|
|
20
|
-
brands?: string[] | null
|
|
21
|
-
excludedBrands?: string[]
|
|
16
|
+
manufacturers?: string[] | null
|
|
17
|
+
excludedManufacturers?: string[]
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
export const NestedSupportedDeviceTable =
|
|
@@ -26,9 +22,8 @@ export const NestedSupportedDeviceTable =
|
|
|
26
22
|
|
|
27
23
|
export function SupportedDeviceTable({
|
|
28
24
|
disableFilter = false,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
excludedBrands = [],
|
|
25
|
+
manufacturers = null,
|
|
26
|
+
excludedManufacturers = [],
|
|
32
27
|
className,
|
|
33
28
|
}: SupportedDeviceTableProps = {}): JSX.Element {
|
|
34
29
|
useComponentTelemetry('SupportedDeviceTable')
|
|
@@ -36,11 +31,9 @@ export function SupportedDeviceTable({
|
|
|
36
31
|
const [filterValue, setFilterValue] = useState('')
|
|
37
32
|
const [filters, setFilters] = useState<DeviceModelFilters>({
|
|
38
33
|
supportedOnly: true,
|
|
39
|
-
|
|
34
|
+
manufacturer: null,
|
|
40
35
|
})
|
|
41
36
|
|
|
42
|
-
const hideFilter = cannotFilter ?? disableFilter
|
|
43
|
-
|
|
44
37
|
return (
|
|
45
38
|
<div
|
|
46
39
|
className={classNames(
|
|
@@ -48,14 +41,14 @@ export function SupportedDeviceTable({
|
|
|
48
41
|
className
|
|
49
42
|
)}
|
|
50
43
|
>
|
|
51
|
-
{!
|
|
44
|
+
{!disableFilter && (
|
|
52
45
|
<SupportedDeviceFilterArea
|
|
53
46
|
filterValue={filterValue}
|
|
54
47
|
setFilterValue={setFilterValue}
|
|
55
48
|
filters={filters}
|
|
56
49
|
setFilters={setFilters}
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
manufacturers={manufacturers}
|
|
51
|
+
excludedManufacturers={excludedManufacturers}
|
|
59
52
|
/>
|
|
60
53
|
)}
|
|
61
54
|
<SupportedDeviceContent
|
|
@@ -64,8 +57,8 @@ export function SupportedDeviceTable({
|
|
|
64
57
|
}}
|
|
65
58
|
filterValue={filterValue}
|
|
66
59
|
filters={filters}
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
manufacturers={manufacturers}
|
|
61
|
+
excludedManufacturers={excludedManufacturers}
|
|
69
62
|
/>
|
|
70
63
|
</div>
|
|
71
64
|
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DeviceModelV1,
|
|
3
|
+
RouteRequestParams,
|
|
4
|
+
RouteResponse,
|
|
5
|
+
} from '@seamapi/types/devicedb'
|
|
6
|
+
import { useQuery } from '@tanstack/react-query'
|
|
7
|
+
import type { SeamError } from 'seamapi'
|
|
8
|
+
|
|
9
|
+
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
10
|
+
import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
|
|
11
|
+
|
|
12
|
+
export type UseDeviceModelParams = DeviceModelsGetParams | string
|
|
13
|
+
export type UseDeviceModelData = DeviceModelV1 | null
|
|
14
|
+
|
|
15
|
+
export function useDeviceModel(
|
|
16
|
+
params?: UseDeviceModelParams
|
|
17
|
+
): UseSeamQueryResult<'deviceModel', UseDeviceModelData> {
|
|
18
|
+
const normalizedParams =
|
|
19
|
+
typeof params === 'string' ? { device_model_id: params } : params
|
|
20
|
+
|
|
21
|
+
const { client: seam } = useSeamClient()
|
|
22
|
+
const { data, ...rest } = useQuery<
|
|
23
|
+
DeviceModelsGetResponse['device_model'] | null,
|
|
24
|
+
SeamError
|
|
25
|
+
>({
|
|
26
|
+
enabled: seam != null,
|
|
27
|
+
queryKey: ['internal', 'device_models', 'get', normalizedParams],
|
|
28
|
+
queryFn: async () => {
|
|
29
|
+
if (seam == null) return null
|
|
30
|
+
const {
|
|
31
|
+
data: { device_model: deviceModel },
|
|
32
|
+
} = await seam.client.get<DeviceModelsGetResponse>(
|
|
33
|
+
'/internal/devicedb/v1/device_models/get',
|
|
34
|
+
{ params: normalizedParams }
|
|
35
|
+
)
|
|
36
|
+
return deviceModel
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
return { ...rest, deviceModel: data }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type DeviceModelsGetParams = RouteRequestParams<'/v1/device_models/get'>
|
|
44
|
+
|
|
45
|
+
type DeviceModelsGetResponse = RouteResponse<'/v1/device_models/get'>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DeviceModelV1,
|
|
3
|
+
RouteRequestParams,
|
|
4
|
+
RouteResponse,
|
|
5
|
+
} from '@seamapi/types/devicedb'
|
|
6
|
+
import { useQuery } from '@tanstack/react-query'
|
|
7
|
+
import type { SeamError } from 'seamapi'
|
|
8
|
+
|
|
9
|
+
import { useSeamClient } from 'lib/seam/use-seam-client.js'
|
|
10
|
+
import type { UseSeamQueryResult } from 'lib/seam/use-seam-query-result.js'
|
|
11
|
+
|
|
12
|
+
export type UseDeviceModelsParams = DeviceModelsListParams
|
|
13
|
+
export type UseDeviceModelsData = DeviceModelV1[]
|
|
14
|
+
|
|
15
|
+
export function useDeviceModels(
|
|
16
|
+
params?: UseDeviceModelsParams
|
|
17
|
+
): UseSeamQueryResult<'deviceModels', UseDeviceModelsData> {
|
|
18
|
+
const { client: seam } = useSeamClient()
|
|
19
|
+
|
|
20
|
+
const { data, ...rest } = useQuery<
|
|
21
|
+
DeviceModelsListResponse['device_models'],
|
|
22
|
+
SeamError
|
|
23
|
+
>({
|
|
24
|
+
enabled: seam != null,
|
|
25
|
+
queryKey: ['internal', 'device_models', 'list', params],
|
|
26
|
+
queryFn: async () => {
|
|
27
|
+
if (seam == null) return []
|
|
28
|
+
const {
|
|
29
|
+
data: { device_models: deviceModels },
|
|
30
|
+
} = await seam.client.get<DeviceModelsListResponse>(
|
|
31
|
+
'/internal/devicedb/v1/device_models/list',
|
|
32
|
+
{ params }
|
|
33
|
+
)
|
|
34
|
+
return deviceModels
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
return { ...rest, deviceModels: data }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type DeviceModelsListParams = RouteRequestParams<'/v1/device_models/list'>
|
|
42
|
+
|
|
43
|
+
type DeviceModelsListResponse = RouteResponse<'/v1/device_models/list'>
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import {
|
|
2
2
|
useDeviceModels,
|
|
3
3
|
type UseDeviceModelsParams,
|
|
4
|
-
} from 'lib/seam/
|
|
4
|
+
} from 'lib/seam/components/SupportedDeviceTable/use-device-models.js'
|
|
5
|
+
|
|
6
|
+
import { useFilteredManufacturers } from './use-filtered-manufacturers.js'
|
|
5
7
|
|
|
6
8
|
export interface DeviceModelFilters {
|
|
7
9
|
supportedOnly: boolean
|
|
8
|
-
|
|
10
|
+
manufacturer: string | null
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export const useFilteredDeviceModels = ({
|
|
12
14
|
filterValue,
|
|
13
15
|
filters,
|
|
14
|
-
|
|
15
|
-
excludedBrands,
|
|
16
|
+
...manufacturersParams
|
|
16
17
|
}: {
|
|
17
18
|
filterValue: string
|
|
18
19
|
filters: DeviceModelFilters
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
manufacturers: string[] | null
|
|
21
|
+
excludedManufacturers: string[]
|
|
21
22
|
}): ReturnType<typeof useDeviceModels> => {
|
|
23
|
+
const { manufacturers } = useFilteredManufacturers(manufacturersParams)
|
|
24
|
+
|
|
22
25
|
const params: UseDeviceModelsParams = {}
|
|
23
26
|
|
|
24
27
|
if (filterValue.trim() !== '') {
|
|
@@ -26,26 +29,34 @@ export const useFilteredDeviceModels = ({
|
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
if (filters.supportedOnly) {
|
|
29
|
-
params.
|
|
32
|
+
params.integration_status = 'stable'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (filters.manufacturer !== null) {
|
|
36
|
+
const manufacturer = manufacturers?.find(
|
|
37
|
+
(manufacturer) => manufacturer.display_name === filters.manufacturer
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (manufacturer != null) {
|
|
41
|
+
params.manufacturer_id = manufacturer.manufacturer_id
|
|
42
|
+
}
|
|
30
43
|
}
|
|
31
44
|
|
|
32
|
-
if (filters.
|
|
33
|
-
params.
|
|
45
|
+
if (filters.manufacturer == null && manufacturers != null) {
|
|
46
|
+
params.manufacturer_ids = manufacturers.map((m) => m.manufacturer_id)
|
|
34
47
|
}
|
|
35
48
|
|
|
36
|
-
const query = useDeviceModels(params)
|
|
49
|
+
const { deviceModels, ...query } = useDeviceModels(params)
|
|
37
50
|
|
|
38
|
-
// UPSTREAM: The API does not have a brands or excludedBrands query parameter,
|
|
39
|
-
// so selected brands are filtered here.
|
|
40
51
|
return {
|
|
41
52
|
...query,
|
|
42
|
-
deviceModels:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
deviceModels: deviceModels?.filter(
|
|
54
|
+
(deviceModel) =>
|
|
55
|
+
manufacturers?.some(
|
|
56
|
+
(manufacturer) =>
|
|
57
|
+
deviceModel.manufacturer.manufacturer_id ===
|
|
58
|
+
manufacturer.manufacturer_id
|
|
59
|
+
)
|
|
60
|
+
),
|
|
50
61
|
}
|
|
51
62
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useManufacturers } from 'lib/seam/components/SupportedDeviceTable/use-manufacturers.js'
|
|
2
|
+
|
|
3
|
+
interface Params {
|
|
4
|
+
manufacturers: string[] | null
|
|
5
|
+
excludedManufacturers: string[]
|
|
6
|
+
}
|
|
7
|
+
export const useFilteredManufacturers = (
|
|
8
|
+
params: Params
|
|
9
|
+
): ReturnType<typeof useManufacturers> => {
|
|
10
|
+
return useManufacturers({
|
|
11
|
+
liqe_query: createLiqeQuery(params),
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const createLiqeQuery = ({
|
|
16
|
+
manufacturers,
|
|
17
|
+
excludedManufacturers,
|
|
18
|
+
}: Params): string | undefined => {
|
|
19
|
+
if (
|
|
20
|
+
(manufacturers?.some(isInvalidInput) ?? false) ||
|
|
21
|
+
excludedManufacturers.some(isInvalidInput)
|
|
22
|
+
) {
|
|
23
|
+
return undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const excludedManufacturersClause = `NOT (${excludedManufacturers
|
|
27
|
+
.map(manufacturerToMatcher)
|
|
28
|
+
.join(' OR ')})`
|
|
29
|
+
|
|
30
|
+
if (manufacturers == null) {
|
|
31
|
+
if (excludedManufacturers.length === 0) return undefined
|
|
32
|
+
return excludedManufacturersClause
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (manufacturers.length === 0) {
|
|
36
|
+
return 'manufacturer_id:none'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const includedManufacturersClause = `(${manufacturers
|
|
40
|
+
.map(manufacturerToMatcher)
|
|
41
|
+
.join(' OR ')})`
|
|
42
|
+
|
|
43
|
+
if (excludedManufacturers.length === 0) return includedManufacturersClause
|
|
44
|
+
|
|
45
|
+
return `${includedManufacturersClause} AND ${excludedManufacturersClause}`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const manufacturerToMatcher = (value: string): string => {
|
|
49
|
+
const [manufacturer, uuid] = value.split('=')
|
|
50
|
+
if (uuid != null) return `manufacturer_id:"${uuid}"`
|
|
51
|
+
return `display_name:"${manufacturer}"`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isInvalidInput = (value: string): boolean => value.includes('"')
|