@integration-app/react 0.2.1 → 0.3.1

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 (56) hide show
  1. package/dist/index.d.ts +371 -165
  2. package/dist/index.js +510 -234
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.module.d.ts +371 -165
  5. package/dist/index.module.mjs +500 -235
  6. package/dist/index.module.mjs.map +1 -1
  7. package/dist/index.umd.d.ts +371 -165
  8. package/dist/index.umd.js +510 -238
  9. package/dist/index.umd.js.map +1 -1
  10. package/package.json +5 -2
  11. package/src/actions/useAction.ts +35 -0
  12. package/src/actions/useActionInstance.ts +56 -0
  13. package/src/actions/useActionInstances.ts +11 -0
  14. package/src/actions/useActions.ts +11 -0
  15. package/src/app-events/useAppEventSubscription.ts +6 -6
  16. package/src/app-events/useAppEventSubscriptions.ts +5 -4
  17. package/src/app-events/useAppEventType.ts +10 -7
  18. package/src/app-events/useAppEventTypes.ts +2 -4
  19. package/src/app-events/useAppEvents.ts +2 -4
  20. package/src/contexts/index.tsx +4 -0
  21. package/src/data-collections/useDataCollectionSpec.ts +26 -0
  22. package/src/data-links/useDataLinkTable.ts +18 -0
  23. package/src/data-links/useDataLinkTableInstance.ts +39 -0
  24. package/src/data-links/useDataLinkTableInstances.ts +19 -0
  25. package/src/data-links/useDataLinkTables.ts +11 -0
  26. package/src/data-sources/useDataSource.ts +29 -6
  27. package/src/data-sources/useDataSourceEvents.ts +2 -4
  28. package/src/data-sources/useDataSourceInstance.ts +120 -26
  29. package/src/data-sources/useDataSourceInstanceCollection.ts +14 -4
  30. package/src/data-sources/useDataSourceInstanceLocations.ts +17 -6
  31. package/src/data-sources/useDataSourceInstances.ts +5 -4
  32. package/src/data-sources/useDataSources.ts +2 -4
  33. package/src/field-mappings/useFieldMapping.ts +29 -8
  34. package/src/field-mappings/useFieldMappingInstance.ts +35 -12
  35. package/src/field-mappings/useFieldMappingInstances.ts +5 -4
  36. package/src/field-mappings/useFieldMappings.ts +2 -4
  37. package/src/flows/useFlow.ts +29 -8
  38. package/src/flows/useFlowInstance.ts +62 -5
  39. package/src/flows/useFlowInstances.ts +2 -4
  40. package/src/flows/useFlowRun.ts +18 -6
  41. package/src/flows/useFlowRuns.ts +5 -5
  42. package/src/flows/useFlows.ts +5 -5
  43. package/src/hooks/useElement.tsx +137 -149
  44. package/src/hooks/useElements.tsx +44 -73
  45. package/src/hooks/useIntegrationAppSWR.tsx +13 -0
  46. package/src/index.tsx +27 -14
  47. package/src/integrations/useConnection.ts +14 -5
  48. package/src/integrations/useConnections.ts +3 -4
  49. package/src/integrations/useConnectorSpec.ts +7 -18
  50. package/src/integrations/useIntegration.ts +11 -7
  51. package/src/integrations/useIntegrations.ts +3 -4
  52. package/src/screens/useScreen.ts +19 -0
  53. package/rollup.dts.config.mjs +0 -21
  54. package/src/flows/useFlowTemplate.ts +0 -0
  55. package/src/flows/useFlowTemplates.ts +0 -0
  56. package/src/hooks/useGetter.tsx +0 -38
@@ -1,187 +1,175 @@
1
- import {
2
- IntegrationAppClient,
3
- ElementAccessor,
4
- ElementInstanceAccessor,
5
- } from '@integration-app/sdk'
6
- import { useEffect, useState } from 'react'
1
+ import { IntegrationAppClient } from '@integration-app/sdk'
2
+ import AwesomeDebouncePromise from 'awesome-debounce-promise'
7
3
  import { useIntegrationApp } from 'contexts/integration-app-context'
4
+ import useSWR from 'swr'
8
5
 
9
- interface ElementHookResult<
10
- ElementInterface,
11
- ElementAccessor,
12
- CreateRequest,
13
- UpdateRequest,
14
- > {
15
- data: ElementInterface | undefined
16
- loading: boolean
17
- error?: Error
18
- create: (data: CreateRequest) => Promise<ElementInterface>
19
- patch: (data: UpdateRequest) => Promise<ElementInterface>
20
- put: (data: CreateRequest) => Promise<ElementInterface>
21
- archive: () => Promise<void>
22
- refresh: () => void
23
- accessor: ElementAccessor
6
+ interface ElementState {
7
+ debouncedPut: (data) => Promise<void>
8
+ updatedLocally: boolean
9
+ savingToServer: boolean
24
10
  }
25
11
 
26
- type ElementAccessorGetter<SelectorInterface, ElementAccessor> = (
27
- params: SelectorInterface | string,
28
- ) => ElementAccessor
12
+ const elementStateCache = new Map<string, ElementState>()
13
+
14
+ interface BaseElementAccessor<Element, UpdateRequest, CreateRequest> {
15
+ get(): Promise<Element>
29
16
 
30
- export type ElementAccessorGenerator<SelectorInterface, ElementAccessor> = (
31
- integrationApp: IntegrationAppClient,
32
- ) => ElementAccessorGetter<SelectorInterface, ElementAccessor>
17
+ patch?(data: Partial<UpdateRequest>): Promise<Element>
18
+
19
+ put?(data: UpdateRequest): Promise<Element>
33
20
 
34
- interface BaseElementAccessor<ElementInterface, CreateRequest, UpdateRequest> {
35
- get(): Promise<ElementInterface>
36
- create?: (data: CreateRequest) => Promise<ElementInterface>
37
- patch?(data: UpdateRequest): Promise<ElementInterface>
38
- put?(data: CreateRequest): Promise<ElementInterface>
39
21
  archive?(): Promise<void>
40
- }
41
22
 
42
- type ExtractElementGenerics<T, Interface> = T extends ElementAccessor<
43
- infer _InterfaceType,
44
- infer CreateRequestType,
45
- infer UpdateRequestType
46
- >
47
- ? { CreateRequest: CreateRequestType; UpdateRequest: UpdateRequestType }
48
- : T extends ElementInstanceAccessor<
49
- infer _ElementInstanceType,
50
- infer _SelectorType,
51
- infer CreateRequestType,
52
- infer UpdateRequestType
53
- >
54
- ? { CreateRequest: CreateRequestType; UpdateRequest: UpdateRequestType }
55
- : { CreateRequest: Partial<Interface>; UpdateRequest: Partial<Interface> }
23
+ create?(data: CreateRequest): Promise<Element>
24
+ }
56
25
 
57
26
  export function useElement<
58
- ElementInterface,
59
- SelectorInterface,
27
+ Element,
28
+ UpdateRequest,
29
+ CreateRequest,
60
30
  ElementAccessor extends BaseElementAccessor<
61
- ElementInterface,
62
- CreateRequest,
63
- UpdateRequest
31
+ Element,
32
+ UpdateRequest,
33
+ CreateRequest
64
34
  >,
65
- CreateRequest extends Partial<ElementInterface> = ExtractElementGenerics<
66
- ElementAccessor,
67
- ElementInterface
68
- >['CreateRequest'],
69
- UpdateRequest extends Partial<ElementInterface> = ExtractElementGenerics<
70
- ElementAccessor,
71
- ElementInterface
72
- >['UpdateRequest'],
73
35
  >(
74
- props: SelectorInterface | { id: string },
75
- accessorGenerator: ElementAccessorGenerator<
76
- SelectorInterface,
77
- ElementAccessor
78
- >,
79
- ): ElementHookResult<
80
- ElementInterface,
81
- ElementAccessor,
82
- CreateRequest,
83
- UpdateRequest
84
- > {
36
+ selector: any,
37
+ accessorGenerator: (
38
+ integrationAppClient: IntegrationAppClient,
39
+ ) => ElementAccessor,
40
+ ) {
85
41
  const integrationApp = useIntegrationApp()
86
- const [data, setData] = useState<ElementInterface>()
87
- const [loading, setLoading] = useState<boolean>(true)
88
- const [error, setError] = useState<Error>(null)
89
- const [refreshCounter, setRefreshCounter] = useState(0)
90
-
91
- function updateDataWith(newData) {
92
- if (data !== undefined) {
93
- setData({
94
- ...data,
95
- ...newData,
96
- })
97
- }
42
+
43
+ // To make sure all instances of useElement with the same IntegrationAppClient and selector
44
+ // are synchronized, we cache them using selector and token as a key
45
+ const elementKeyData: any = {
46
+ token: integrationApp.token,
47
+ selector,
48
+ }
49
+ const elementKey = JSON.stringify(elementKeyData)
50
+
51
+ if (!elementStateCache.has(elementKey)) {
52
+ elementStateCache.set(elementKey, {
53
+ updatedLocally: false,
54
+ savingToServer: false,
55
+ debouncedPut: AwesomeDebouncePromise(async (data) => {
56
+ elementState.updatedLocally = false
57
+ elementState.savingToServer = true
58
+
59
+ try {
60
+ const result = await accessor?.put(data)
61
+ if (!elementState.updatedLocally) {
62
+ // Update savingToSever so that cached versions in each hook are updated when they react to 'mutate' below
63
+ // Yes, this duplicates the one in `finally`, but but the time that one is called it's too late since `mutate` already did its job.
64
+ elementState.savingToServer = false
65
+ // When we received updated state of the element,
66
+ // apply it to the context as long as we didn't make any other changes locally
67
+ // meanwhile.
68
+ await mutate(result, false)
69
+ }
70
+ } catch (e) {
71
+ elementState.updatedLocally = true
72
+ throw e
73
+ } finally {
74
+ elementState.savingToServer = false
75
+ }
76
+ }, 500),
77
+ })
98
78
  }
99
79
 
100
- function replaceDataWith(newData) {
101
- setData(newData)
80
+ const elementState = elementStateCache.get(elementKey)
81
+
82
+ const accessor = integrationApp ? accessorGenerator(integrationApp) : null
83
+
84
+ const swrKey = accessor && selector ? `element:${elementKey}` : null // do not fetch anything if selector or accessor is not defined
85
+
86
+ const {
87
+ data: item,
88
+ mutate,
89
+ error,
90
+ isLoading,
91
+ isValidating,
92
+ } = useSWR(swrKey, () => accessor?.get(), {
93
+ // pause revalidation if update is in progress to not overwrite local changes
94
+ isPaused: () => elementState.updatedLocally || elementState.savingToServer,
95
+ })
96
+
97
+ const loading = isLoading
98
+ const refreshing = isValidating
99
+
100
+ async function refresh(): Promise<Element> {
101
+ return await mutate()
102
102
  }
103
103
 
104
- const selector = (props as any)?.id
105
- ? (props as { id: string }).id
106
- : (props as SelectorInterface)
107
-
108
- const accessor = integrationApp
109
- ? accessorGenerator(integrationApp)(selector)
110
- : null
111
-
112
- useEffect(() => {
113
- setLoading(true)
114
- setError(null)
115
- if (integrationApp && selector) {
116
- accessor
117
- .get()
118
- .then(setData)
119
- .catch(setError)
120
- .finally(() => setLoading(false))
121
- } else {
122
- setError(
123
- new Error(
124
- 'IntegrationApp not found. Was this component wrapped in <IntegrationAppProvider>?',
125
- ),
104
+ async function put(data: UpdateRequest) {
105
+ if (!accessor?.put) {
106
+ throw new Error(
107
+ `"put method is not supported for accessor ${accessor.constructor.name}`,
126
108
  )
127
109
  }
128
- }, [
129
- integrationApp,
130
- JSON.stringify(selector),
131
- JSON.stringify(props),
132
- refreshCounter,
133
- ])
134
-
135
- async function create(createData: CreateRequest) {
136
- // Because `createData` do not contain all critical fields
137
- // we do not update state with `createData` to avoid problem
138
- // with missing critical fields like `id`
139
-
140
- const returnedData = await accessor.create(createData)
141
- replaceDataWith(returnedData)
142
- return returnedData
143
- }
144
-
145
- function refresh() {
146
- setRefreshCounter(refreshCounter + 1)
147
- }
148
110
 
149
- async function patch(patch: UpdateRequest) {
150
- if (typeof patch === 'object') {
151
- updateDataWith(patch ?? {})
111
+ elementState.updatedLocally = true
152
112
 
153
- // TODO: PL-3550
154
- // PATCH could response with modified fields that do not exist in `patch`
155
- // but this data could be outdated because of other methods calls
156
- return accessor.patch(patch)
157
- } else {
158
- return data
113
+ // We don't know which fields are "innate" for the element and should stay
114
+ // and which should be removed by put, so we'll do a simple patch.
115
+ // We'll update data with actual value from the server after put is done.
116
+ const newLocalData = {
117
+ ...item,
118
+ ...data,
159
119
  }
120
+
121
+ await mutate(newLocalData, false)
122
+
123
+ await elementState.debouncedPut(data)
160
124
  }
161
125
 
162
- async function put(putData: CreateRequest) {
163
- updateDataWith(putData)
126
+ async function patch(data: Partial<UpdateRequest>) {
127
+ const newData = {
128
+ ...item,
129
+ ...data,
130
+ } as UpdateRequest
164
131
 
165
- // TODO: PL-3550
166
- // PUT could response with modified fields that do not exist in `patch`
167
- // but this data could be outdated because of other methods calls
168
- return await accessor.put(putData)
132
+ return put(newData)
169
133
  }
170
134
 
171
135
  async function archive() {
172
- setData(null)
173
- return accessor.archive()
136
+ if (!accessor?.archive) {
137
+ return
138
+ }
139
+
140
+ await mutate({ ...item, archivedAt: new Date().toISOString() }, false)
141
+ await accessor?.archive()
142
+ await mutate()
143
+ }
144
+
145
+ async function create(data: CreateRequest) {
146
+ if (!accessor?.create) {
147
+ throw new Error(
148
+ `"create method is not supported for accessor ${accessor.constructor.name}`,
149
+ )
150
+ }
151
+
152
+ const result = await accessor?.create(data)
153
+
154
+ return await mutate(result)
174
155
  }
175
156
 
176
157
  return {
177
- data,
158
+ accessor,
159
+
160
+ item,
161
+
162
+ loading,
163
+ saving: elementState.updatedLocally || elementState.savingToServer,
164
+
165
+ error,
166
+
167
+ refresh,
168
+ refreshing,
169
+
178
170
  create,
179
171
  patch,
180
172
  put,
181
173
  archive,
182
- refresh,
183
- loading,
184
- error,
185
- accessor,
186
174
  }
187
175
  }
@@ -1,98 +1,69 @@
1
1
  import { useIntegrationApp } from '../contexts/integration-app-context'
2
- import { useEffect, useRef, useState } from 'react'
3
- import { IntegrationAppClient } from '@integration-app/sdk'
4
- import { PaginationQuery, PaginationResponse } from '@integration-app/sdk'
5
-
6
- export interface ElementsHookResult<Element> {
7
- items: Element[]
8
- loading: boolean
9
- error?: Error
10
- refresh(): Promise<void>
11
- loadMore(): Promise<void>
12
- }
13
-
14
- interface ElementsAccessor<Element, FindQuery> {
15
- find(query: FindQuery): Promise<PaginationResponse<Element>>
16
- }
2
+ import { useState } from 'react'
3
+ import { PaginationResponse } from '@integration-app/sdk'
4
+ import useSWRInfinite from 'swr/infinite'
5
+ import qs from 'query-string'
17
6
 
18
- type InstanceAccessorGenerator<Element, FindQuery> = (
19
- integrationApp: IntegrationAppClient,
20
- ) => ElementsAccessor<Element, FindQuery>
7
+ const LIMIT = 25
21
8
 
22
- export function useElements<Element, FindQuery extends PaginationQuery>(
23
- initialQuery: FindQuery,
24
- accessorGenerator: InstanceAccessorGenerator<Element, FindQuery>,
25
- ): ElementsHookResult<Element> {
9
+ export function useElements<Item>(route: string, query = {}) {
26
10
  const integrationApp = useIntegrationApp()
27
11
 
28
- const refreshId = useRef<number>(0)
29
- const [items, setItems] = useState<Element[]>([])
30
- const [nextCursor, setNextCursor] = useState<any>(undefined)
31
- const [loading, setLoading] = useState<boolean>(false)
32
- const [error, setError] = useState<Error>(null)
12
+ function getKey(
13
+ page: number,
14
+ previousPageData: PaginationResponse<Item> | null,
15
+ ) {
16
+ // first page, we don't have `previousPageData`
17
+ if (page === 0)
18
+ return `/${route}?${qs.stringify({
19
+ ...query,
20
+ limit: LIMIT,
21
+ })}`
22
+
23
+ // reached the end
24
+ if (previousPageData.items?.length < LIMIT) return null
25
+
26
+ return `/${route}?${qs.stringify({
27
+ ...query,
28
+ limit: LIMIT,
29
+ cursor: previousPageData.cursor,
30
+ })}`
31
+ }
33
32
 
34
- async function loadMore() {
35
- const startingRefreshId = refreshId.current
36
- const isFirstPage = !nextCursor
37
-
38
- function setStateIfCurrentRefresh(stateSetter, valueGetter: (arg) => any) {
39
- // If the refreshId has changed since the beginning of this function,
40
- // it means refresh() was called while we were loading more results.
41
- // Don't change the state in that case - the latest refresh will take care of that.
42
- stateSetter((value) =>
43
- startingRefreshId === refreshId.current ? valueGetter(value) : value,
44
- )
45
- }
33
+ const [loadingMore, setIsLoadingMore] = useState(false)
46
34
 
47
- setStateIfCurrentRefresh(setError, () => null)
48
- setStateIfCurrentRefresh(setLoading, () => true)
35
+ const { data, size, setSize, isLoading, error, mutate, isValidating } =
36
+ useSWRInfinite<PaginationResponse<Item>>(getKey, (url) =>
37
+ integrationApp.get(url),
38
+ )
49
39
 
50
- const queryParams = {
51
- ...initialQuery,
52
- }
40
+ const items = data ? data.map((page) => page.items).flat() : []
53
41
 
54
- if (nextCursor) queryParams.cursor = nextCursor
42
+ const loading = isLoading
43
+ const refreshing = isValidating
55
44
 
56
- try {
57
- const data = await accessorGenerator(integrationApp).find(queryParams)
45
+ async function loadMore() {
46
+ const hasMoreToLoad = data[size - 1]?.items?.length === LIMIT
58
47
 
59
- setStateIfCurrentRefresh(setNextCursor, () => data.cursor)
60
- setStateIfCurrentRefresh(setItems, (items) =>
61
- isFirstPage ? data.items : [...items, ...data.items],
62
- )
63
- } catch (e) {
64
- setStateIfCurrentRefresh(setError, () => e)
65
- } finally {
66
- setStateIfCurrentRefresh(setLoading, () => false)
48
+ if (hasMoreToLoad) {
49
+ setIsLoadingMore(true)
50
+ await setSize(size + 1)
51
+ setIsLoadingMore(false)
67
52
  }
68
53
  }
69
54
 
70
- // refresh on initialQuery change
71
- useEffect(() => {
72
- if (!integrationApp) {
73
- setError(
74
- new Error(
75
- 'IntegrationApp not found. Was this component wrapped in <IntegrationAppProvider>?',
76
- ),
77
- )
78
-
79
- return
80
- }
81
-
82
- refresh()
83
- }, [integrationApp, JSON.stringify(initialQuery)])
84
-
85
55
  async function refresh() {
86
- refreshId.current += 1
87
- setNextCursor(undefined)
88
- await loadMore()
56
+ await mutate()
89
57
  }
90
58
 
91
59
  return {
92
60
  items,
93
61
 
94
62
  refresh,
63
+ refreshing,
64
+
95
65
  loadMore,
66
+ loadingMore,
96
67
 
97
68
  loading,
98
69
 
@@ -0,0 +1,13 @@
1
+ import useSWR from 'swr'
2
+ import { useIntegrationApp } from '../contexts/integration-app-context'
3
+
4
+ export function useIntegrationAppSWR(path: string, options?: any) {
5
+ const client = useIntegrationApp()
6
+
7
+ const fetcher = async () => {
8
+ const response = await client.get(path, options)
9
+ return response
10
+ }
11
+
12
+ return useSWR(client ? path : undefined, fetcher, options)
13
+ }
package/src/index.tsx CHANGED
@@ -1,32 +1,31 @@
1
- export {
2
- useIntegrationApp,
3
- IntegrationAppProvider,
4
- } from './contexts/integration-app-context.js'
1
+ export * from './contexts/index.js'
5
2
 
3
+ export { useIntegrationAppSWR } from './hooks/useIntegrationAppSWR.js'
4
+
5
+ export { useConnection } from './integrations/useConnection.js'
6
+ export { useConnections } from './integrations/useConnections.js'
6
7
  export { useConnectorSpec } from './integrations/useConnectorSpec.js'
7
8
  export { useIntegration } from './integrations/useIntegration.js'
8
9
  export { useIntegrations } from './integrations/useIntegrations.js'
9
- export { useConnection } from './integrations/useConnection.js'
10
- export { useConnections } from './integrations/useConnections.js'
11
10
 
12
11
  export { useFieldMapping } from './field-mappings/useFieldMapping.js'
13
- export { useFieldMappings } from './field-mappings/useFieldMappings.js'
14
12
  export { useFieldMappingInstance } from './field-mappings/useFieldMappingInstance.js'
15
13
  export { useFieldMappingInstances } from './field-mappings/useFieldMappingInstances.js'
14
+ export { useFieldMappings } from './field-mappings/useFieldMappings.js'
16
15
 
17
16
  export { useDataSource } from './data-sources/useDataSource.js'
18
- export { useDataSources } from './data-sources/useDataSources.js'
17
+ export { useDataSourceEvents } from './data-sources/useDataSourceEvents.js'
19
18
  export { useDataSourceInstance } from './data-sources/useDataSourceInstance.js'
19
+ export { useDataSourceInstanceCollection } from './data-sources/useDataSourceInstanceCollection.js'
20
+ export { useDataSourceInstanceLocations } from './data-sources/useDataSourceInstanceLocations.js'
20
21
  export { useDataSourceInstances } from './data-sources/useDataSourceInstances.js'
21
- export { useDataSourceInstanceCollection as useDataSourceCollection } from './data-sources/useDataSourceInstanceCollection.js'
22
- export { useDataSourceInstanceLocations as useDataSourceLocations } from './data-sources/useDataSourceInstanceLocations.js'
23
- export { useDataSourceEvents } from './data-sources/useDataSourceEvents.js'
22
+ export { useDataSources } from './data-sources/useDataSources.js'
24
23
 
25
- export { useAppEvents } from './app-events/useAppEvents.js'
26
- export { useAppEventType } from './app-events/useAppEventType.js'
27
- export { useAppEventTypes } from './app-events/useAppEventTypes.js'
28
24
  export { useAppEventSubscription } from './app-events/useAppEventSubscription.js'
29
25
  export { useAppEventSubscriptions } from './app-events/useAppEventSubscriptions.js'
26
+ export { useAppEventType } from './app-events/useAppEventType.js'
27
+ export { useAppEventTypes } from './app-events/useAppEventTypes.js'
28
+ export { useAppEvents } from './app-events/useAppEvents.js'
30
29
 
31
30
  export { useFlow } from './flows/useFlow.js'
32
31
  export { useFlows } from './flows/useFlows.js'
@@ -37,4 +36,18 @@ export { useFlowInstances } from './flows/useFlowInstances.js'
37
36
  export { useFlowRun } from './flows/useFlowRun.js'
38
37
  export { useFlowRuns } from './flows/useFlowRuns.js'
39
38
 
39
+ export { useDataLinkTable } from './data-links/useDataLinkTable.js'
40
+ export { useDataLinkTableInstance } from './data-links/useDataLinkTableInstance.js'
41
+ export { useDataLinkTableInstances } from './data-links/useDataLinkTableInstances.js'
42
+ export { useDataLinkTables } from './data-links/useDataLinkTables.js'
43
+
44
+ export { useAction } from './actions/useAction.js'
45
+ export { useActionInstance } from './actions/useActionInstance.js'
46
+ export { useActionInstances } from './actions/useActionInstances.js'
47
+ export { useActions } from './actions/useActions.js'
48
+
49
+ export { useScreen } from './screens/useScreen.js'
50
+
51
+ export { useDataCollectionSpec } from './data-collections/useDataCollectionSpec.js'
52
+
40
53
  export { DataForm } from '@integration-app/sdk'
@@ -1,12 +1,21 @@
1
- import { Connection, ConnectionAccessor } from '@integration-app/sdk'
1
+ import {
2
+ Connection,
3
+ ConnectionAccessor,
4
+ CreateConnectionRequest,
5
+ UpdateConnectionRequest,
6
+ } from '@integration-app/sdk'
2
7
  import { useElement } from '../hooks/useElement'
3
8
 
4
9
  export function useConnection(id: string) {
5
- const { data: connection, ...rest } = useElement<
10
+ const { item: connection, ...rest } = useElement<
6
11
  Connection,
7
- string,
12
+ UpdateConnectionRequest,
13
+ CreateConnectionRequest,
8
14
  ConnectionAccessor
9
- >(id, (integrationApp) => integrationApp.connection.bind(integrationApp))
15
+ >(id, (integrationApp) => integrationApp.connection(id))
10
16
 
11
- return { connection, ...rest }
17
+ return {
18
+ connection,
19
+ ...rest,
20
+ }
12
21
  }
@@ -2,12 +2,11 @@ import { Connection, FindConnectionsQuery } from '@integration-app/sdk'
2
2
  import { useElements } from '../hooks/useElements'
3
3
 
4
4
  export function useConnections(query?: FindConnectionsQuery) {
5
- const { ...rest } = useElements<Connection, FindConnectionsQuery>(
6
- query,
7
- (integrationApp) => integrationApp.connections,
8
- )
5
+ const { ...rest } = useElements<Connection>('connections', query)
9
6
 
10
7
  return {
8
+ connections: rest.items,
9
+
11
10
  ...rest,
12
11
  }
13
12
  }
@@ -1,25 +1,14 @@
1
1
  import { ConnectionSpec } from '@integration-app/sdk'
2
- import { useEffect, useState } from 'react'
3
2
  import { useIntegrationApp } from '../contexts/integration-app-context'
3
+ import useSWR from 'swr'
4
4
 
5
- export function useConnectorSpec(integrationKey: string) {
5
+ export function useConnectorSpec(integrationIdOrKey: string) {
6
6
  const integrationApp = useIntegrationApp()
7
- const [data, setData] = useState<ConnectionSpec | null>(null)
8
- const [loading, setLoading] = useState(true)
9
- const [error, setError] = useState<Error>(null)
10
7
 
11
- useEffect(() => {
12
- if (!integrationApp) {
13
- return
14
- }
8
+ const { data, isLoading, error } = useSWR<ConnectionSpec>(
9
+ `/integrations/${integrationIdOrKey}/connector-spec`,
10
+ () => integrationApp.integration(integrationIdOrKey).getConnectorSpec(),
11
+ )
15
12
 
16
- integrationApp
17
- .integration(integrationKey)
18
- .getConnectorSpec()
19
- .then(setData)
20
- .catch(setError)
21
- .finally(() => setLoading(false))
22
- }, [integrationApp, integrationKey])
23
-
24
- return { data, loading, error }
13
+ return { data, loading: isLoading, error }
25
14
  }
@@ -1,14 +1,18 @@
1
- import { Integration, IntegrationAccessor } from '@integration-app/sdk'
1
+ import {
2
+ CreateIntegrationRequest,
3
+ Integration,
4
+ IntegrationAccessor,
5
+ UpdateIntegrationRequest,
6
+ } from '@integration-app/sdk'
2
7
  import { useElement } from '../hooks/useElement'
3
8
 
4
- export function useIntegration(idOrKey: string) {
5
- const { data: integration, ...rest } = useElement<
9
+ export function useIntegration(id: string) {
10
+ const { item: integration, ...rest } = useElement<
6
11
  Integration,
7
- string,
12
+ UpdateIntegrationRequest,
13
+ CreateIntegrationRequest,
8
14
  IntegrationAccessor
9
- >(idOrKey, (integrationApp) =>
10
- integrationApp.integration.bind(integrationApp),
11
- )
15
+ >(id, (integrationApp) => integrationApp.integration(id))
12
16
 
13
17
  return { integration, ...rest }
14
18
  }
@@ -2,12 +2,11 @@ import { FindIntegrationsQuery, Integration } from '@integration-app/sdk'
2
2
  import { useElements } from '../hooks/useElements'
3
3
 
4
4
  export function useIntegrations(query?: FindIntegrationsQuery) {
5
- const { ...rest } = useElements<Integration, FindIntegrationsQuery>(
6
- query,
7
- (integrationApp) => integrationApp.integrations,
8
- )
5
+ const { ...rest } = useElements<Integration>('integrations', query)
9
6
 
10
7
  return {
8
+ integrations: rest.items,
9
+
11
10
  ...rest,
12
11
  }
13
12
  }