@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.
Files changed (132) hide show
  1. package/README.md +16 -4
  2. package/dist/elements.js +5533 -5359
  3. package/dist/elements.js.map +1 -1
  4. package/dist/index.css +17 -19
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.min.css +1 -1
  7. package/dist/index.min.css.map +1 -1
  8. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.d.ts +1 -1
  9. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js +11 -13
  10. package/lib/seam/components/AccessCodeDetails/AccessCodeDetails.js.map +1 -1
  11. package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.d.ts +4 -1
  12. package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js +3 -2
  13. package/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.js.map +1 -1
  14. package/lib/seam/components/AccessCodeTable/AccessCodeTable.d.ts +1 -5
  15. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js +15 -11
  16. package/lib/seam/components/AccessCodeTable/AccessCodeTable.js.map +1 -1
  17. package/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.d.ts +1 -1
  18. package/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js +2 -2
  19. package/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.js.map +1 -1
  20. package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.d.ts +1 -1
  21. package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js +12 -7
  22. package/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.js.map +1 -1
  23. package/lib/seam/components/DeviceDetails/LockDeviceDetails.js +11 -4
  24. package/lib/seam/components/DeviceDetails/LockDeviceDetails.js.map +1 -1
  25. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.d.ts +1 -1
  26. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js +4 -4
  27. package/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.js.map +1 -1
  28. package/lib/seam/components/DeviceTable/DeviceHealthBar.d.ts +3 -1
  29. package/lib/seam/components/DeviceTable/DeviceHealthBar.js +4 -3
  30. package/lib/seam/components/DeviceTable/DeviceHealthBar.js.map +1 -1
  31. package/lib/seam/components/DeviceTable/DeviceTable.d.ts +1 -5
  32. package/lib/seam/components/DeviceTable/DeviceTable.js +14 -9
  33. package/lib/seam/components/DeviceTable/DeviceTable.js.map +1 -1
  34. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.d.ts +3 -3
  35. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js +11 -17
  36. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.js.map +1 -1
  37. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.d.ts +1 -1
  38. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.js +1 -7
  39. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.js.map +1 -1
  40. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.d.ts +3 -3
  41. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js +12 -31
  42. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.js.map +1 -1
  43. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.d.ts +2 -2
  44. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.js +2 -4
  45. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.js.map +1 -1
  46. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceManufacturerSection.d.ts +8 -0
  47. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceManufacturerSection.js +35 -0
  48. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceManufacturerSection.js.map +1 -0
  49. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.d.ts +2 -1
  50. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js +10 -6
  51. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.js.map +1 -1
  52. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.d.ts +3 -7
  53. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js +4 -5
  54. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.js.map +1 -1
  55. package/lib/seam/components/SupportedDeviceTable/use-device-model.d.ts +7 -0
  56. package/lib/seam/components/SupportedDeviceTable/use-device-model.js +18 -0
  57. package/lib/seam/components/SupportedDeviceTable/use-device-model.js.map +1 -0
  58. package/lib/seam/components/SupportedDeviceTable/use-device-models.d.ts +7 -0
  59. package/lib/seam/components/SupportedDeviceTable/use-device-models.js +17 -0
  60. package/lib/seam/components/SupportedDeviceTable/use-device-models.js.map +1 -0
  61. package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.d.ts +5 -5
  62. package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js +16 -17
  63. package/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.js.map +1 -1
  64. package/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.d.ts +8 -0
  65. package/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.js +37 -0
  66. package/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.js.map +1 -0
  67. package/lib/seam/components/SupportedDeviceTable/use-manufacturer.d.ts +7 -0
  68. package/lib/seam/components/SupportedDeviceTable/use-manufacturer.js +18 -0
  69. package/lib/seam/components/SupportedDeviceTable/use-manufacturer.js.map +1 -0
  70. package/lib/seam/components/SupportedDeviceTable/use-manufacturers.d.ts +7 -0
  71. package/lib/seam/components/SupportedDeviceTable/use-manufacturers.js +17 -0
  72. package/lib/seam/components/SupportedDeviceTable/use-manufacturers.js.map +1 -0
  73. package/lib/seam/components/common-props.d.ts +3 -0
  74. package/lib/seam/components/common-props.js.map +1 -1
  75. package/lib/seam/filters.d.ts +8 -0
  76. package/lib/seam/filters.js +16 -0
  77. package/lib/seam/filters.js.map +1 -0
  78. package/lib/telemetry/client.js.map +1 -1
  79. package/lib/ui/Snackbar/Snackbar.d.ts +1 -1
  80. package/lib/ui/Snackbar/Snackbar.js +1 -1
  81. package/lib/ui/Snackbar/Snackbar.js.map +1 -1
  82. package/lib/version.d.ts +1 -1
  83. package/lib/version.js +1 -1
  84. package/lib/version.js.map +1 -1
  85. package/package.json +14 -4
  86. package/src/lib/element.tsx +2 -0
  87. package/src/lib/seam/components/AccessCodeDetails/AccessCodeDetails.tsx +24 -30
  88. package/src/lib/seam/components/AccessCodeTable/AccessCodeHealthBar.tsx +9 -1
  89. package/src/lib/seam/components/AccessCodeTable/AccessCodeTable.tsx +34 -13
  90. package/src/lib/seam/components/ClimateSettingScheduleDetails/ClimateSettingScheduleDetails.tsx +4 -0
  91. package/src/lib/seam/components/ClimateSettingScheduleTable/ClimateSettingScheduleTable.tsx +21 -5
  92. package/src/lib/seam/components/DeviceDetails/LockDeviceDetails.tsx +19 -8
  93. package/src/lib/seam/components/DeviceDetails/ThermostatDeviceDetails.tsx +6 -2
  94. package/src/lib/seam/components/DeviceTable/DeviceHealthBar.tsx +10 -2
  95. package/src/lib/seam/components/DeviceTable/DeviceTable.tsx +31 -15
  96. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContent.tsx +23 -29
  97. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceContentRows.tsx +3 -9
  98. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterArea.tsx +22 -41
  99. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceFilterResultRow.tsx +8 -12
  100. package/src/lib/seam/components/SupportedDeviceTable/{SupportedDeviceBrandSection.tsx → SupportedDeviceManufacturerSection.tsx} +19 -26
  101. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceRow.tsx +20 -11
  102. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.element.ts +2 -3
  103. package/src/lib/seam/components/SupportedDeviceTable/SupportedDeviceTable.tsx +10 -17
  104. package/src/lib/seam/components/SupportedDeviceTable/use-device-model.ts +45 -0
  105. package/src/lib/seam/components/SupportedDeviceTable/use-device-models.ts +43 -0
  106. package/src/lib/seam/components/SupportedDeviceTable/use-filtered-device-models.ts +31 -20
  107. package/src/lib/seam/components/SupportedDeviceTable/use-filtered-manufacturers.ts +54 -0
  108. package/src/lib/seam/components/SupportedDeviceTable/use-manufacturer.ts +45 -0
  109. package/src/lib/seam/components/SupportedDeviceTable/use-manufacturers.ts +43 -0
  110. package/src/lib/seam/components/common-props.tsx +10 -0
  111. package/src/lib/seam/filters.ts +32 -0
  112. package/src/lib/telemetry/client.ts +3 -3
  113. package/src/lib/ui/Snackbar/Snackbar.tsx +2 -2
  114. package/src/lib/version.ts +1 -1
  115. package/src/styles/_device-details.scss +1 -2
  116. package/src/styles/_supported-device-table.scss +4 -4
  117. package/src/styles/_thermostat.scss +1 -2
  118. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceBrandSection.d.ts +0 -8
  119. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceBrandSection.js +0 -42
  120. package/lib/seam/components/SupportedDeviceTable/SupportedDeviceBrandSection.js.map +0 -1
  121. package/lib/seam/components/SupportedDeviceTable/use-device-provider.d.ts +0 -2
  122. package/lib/seam/components/SupportedDeviceTable/use-device-provider.js +0 -13
  123. package/lib/seam/components/SupportedDeviceTable/use-device-provider.js.map +0 -1
  124. package/lib/seam/device-models/use-device-models.d.ts +0 -5
  125. package/lib/seam/device-models/use-device-models.js +0 -19
  126. package/lib/seam/device-models/use-device-models.js.map +0 -1
  127. package/lib/strings.d.ts +0 -1
  128. package/lib/strings.js +0 -4
  129. package/lib/strings.js.map +0 -1
  130. package/src/lib/seam/components/SupportedDeviceTable/use-device-provider.ts +0 -16
  131. package/src/lib/seam/device-models/use-device-models.ts +0 -39
  132. 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
- brands: string[] | null
17
- excludedBrands: string[]
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
- brands,
26
- excludedBrands,
25
+ manufacturers,
26
+ excludedManufacturers,
27
27
  }: SupportedDeviceFilterAreaProps): JSX.Element {
28
28
  const appliedFiltersCount = getAppliedFilterCount(filters)
29
29
 
30
- const availableBrands = useAvailableBrands(brands, excludedBrands)
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.brand}
70
+ label={t.manufacturer}
68
71
  allLabel={allLabel}
69
- options={availableBrands}
70
- onSelect={(brand: string) => {
72
+ options={
73
+ availableManufacturers?.map(
74
+ (manufacturer) => manufacturer.display_name
75
+ ) ?? []
76
+ }
77
+ onSelect={(manufacturer: string) => {
71
78
  setFilters((filters) => ({
72
79
  ...filters,
73
- brand,
80
+ manufacturer,
74
81
  }))
75
82
  }}
76
- buttonLabel={filters.brand ?? allLabel}
83
+ buttonLabel={filters.manufacturer ?? allLabel}
77
84
  onAllOptionSelect={() => {
78
- resetFilter('brand')
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.brand !== null) count++
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
- brand: 'Brand',
135
+ manufacturer: 'Manufacturer',
155
136
  supported: 'Supported',
156
137
  filter: 'Filter',
157
138
  filters: 'Filters',
@@ -1,15 +1,13 @@
1
- import type { DeviceModel } from 'seamapi'
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: 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={deviceProvider.image_url}
37
- alt={deviceModel.brand}
38
- className='seam-brand-image'
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.model_name}</div>
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.manufacturer_model_id}
40
+ {deviceModel.device_model_id}
45
41
  <DotDivider />
46
- {connectionTypeNames[deviceModel.connection_type]}
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 { useDeviceProvider } from 'lib/seam/components/SupportedDeviceTable/use-device-provider.js'
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 we collapse
13
- * the list, and require the user to click to
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 SupportedDeviceBrandSectionProps {
19
- brand: string
20
- deviceModels: DeviceModel[]
17
+ interface SupportedDeviceManufacturerSectionProps {
18
+ manufacturerId: string
19
+ deviceModels: DeviceModelV1[]
21
20
  }
22
21
 
23
- export function SupportedDeviceBrandSection({
24
- brand,
22
+ export function SupportedDeviceManufacturerSection({
23
+ manufacturerId,
25
24
  deviceModels,
26
- }: SupportedDeviceBrandSectionProps): JSX.Element | null {
27
- const deviceProvider = useDeviceProvider(brand)
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-brand-section', {
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={deviceProvider.image_url}
58
- alt={brand}
59
- className='seam-brand-image'
56
+ src={manufacturer?.logo?.url}
57
+ alt={manufacturer?.display_name}
58
+ className='seam-manufacturer-image'
60
59
  />
61
- <h5 className='seam-brand-name'>
62
- {deviceProvider.display_name} {t.devices}
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, index) => (
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: 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 width={40} src={deviceModel.icon_url} />
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.model_name}</div>
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.manufacturer_model_id}
48
+ {deviceModel.device_model_id}
45
49
  <DotDivider />
46
- {connectionTypeNames[deviceModel.connection_type]}
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 = supportLevelColors[deviceModel.support_level] ?? 'unknown'
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.support_level]}</span>
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
- DeviceModel['support_level'],
73
+ DeviceModelV1['manufacturer']['integration'],
69
74
  'green' | 'blue' | 'unknown'
70
75
  > = {
71
- live: 'green',
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<DeviceModel['support_level'], string> = {
77
- live: 'LIVE',
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
- brands: 'array',
11
- excludedBrands: 'array',
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
- * @deprecated Use disableFilter.
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
- cannotFilter,
30
- brands = null,
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
- brand: null,
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
- {!hideFilter && (
44
+ {!disableFilter && (
52
45
  <SupportedDeviceFilterArea
53
46
  filterValue={filterValue}
54
47
  setFilterValue={setFilterValue}
55
48
  filters={filters}
56
49
  setFilters={setFilters}
57
- brands={brands}
58
- excludedBrands={excludedBrands}
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
- brands={brands}
68
- excludedBrands={excludedBrands}
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/device-models/use-device-models.js'
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
- brand: string | null
10
+ manufacturer: string | null
9
11
  }
10
12
 
11
13
  export const useFilteredDeviceModels = ({
12
14
  filterValue,
13
15
  filters,
14
- brands,
15
- excludedBrands,
16
+ ...manufacturersParams
16
17
  }: {
17
18
  filterValue: string
18
19
  filters: DeviceModelFilters
19
- brands: string[] | null
20
- excludedBrands: string[]
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.support_level = 'live'
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.brand !== null) {
33
- params.brand = filters.brand
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: query.deviceModels
43
- ?.filter(({ brand }) => {
44
- if (brands === null) return true
45
- return brands.includes(brand)
46
- })
47
- .filter(({ brand }) => {
48
- return !excludedBrands.includes(brand)
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('"')