@commercetools-frontend-extensions/operations 0.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/CHANGELOG.md +55 -0
- package/README.md +169 -0
- package/babel.config.js +6 -0
- package/dist/commercetools-frontend-extensions-operations.cjs.d.ts +2 -0
- package/dist/commercetools-frontend-extensions-operations.cjs.dev.js +2469 -0
- package/dist/commercetools-frontend-extensions-operations.cjs.js +7 -0
- package/dist/commercetools-frontend-extensions-operations.cjs.prod.js +2461 -0
- package/dist/commercetools-frontend-extensions-operations.esm.js +2316 -0
- package/dist/declarations/src/@api/export-operations.d.ts +5 -0
- package/dist/declarations/src/@api/fetcher.d.ts +17 -0
- package/dist/declarations/src/@api/file-upload.d.ts +3 -0
- package/dist/declarations/src/@api/import-containers.d.ts +35 -0
- package/dist/declarations/src/@api/import-operations.d.ts +6 -0
- package/dist/declarations/src/@api/index.d.ts +8 -0
- package/dist/declarations/src/@api/process-file.d.ts +3 -0
- package/dist/declarations/src/@api/test-fixtures.d.ts +272 -0
- package/dist/declarations/src/@api/urls.d.ts +44 -0
- package/dist/declarations/src/@components/file-drop-area/active-drag-drop-area.d.ts +10 -0
- package/dist/declarations/src/@components/file-drop-area/disabled-drop-area.d.ts +5 -0
- package/dist/declarations/src/@components/file-drop-area/drop-area-wrapper.d.ts +11 -0
- package/dist/declarations/src/@components/file-drop-area/enabled-drop-area.d.ts +7 -0
- package/dist/declarations/src/@components/file-drop-area/file-drop-area.d.ts +14 -0
- package/dist/declarations/src/@components/file-drop-area/file-dropped-area.d.ts +6 -0
- package/dist/declarations/src/@components/file-drop-area/index.d.ts +7 -0
- package/dist/declarations/src/@components/file-drop-area/styles.d.ts +9 -0
- package/dist/declarations/src/@components/icons/file-icon.d.ts +2 -0
- package/dist/declarations/src/@components/icons/index.d.ts +2 -0
- package/dist/declarations/src/@components/icons/lock-icon.d.ts +2 -0
- package/dist/declarations/src/@components/index.d.ts +6 -0
- package/dist/declarations/src/@components/info-box/index.d.ts +1 -0
- package/dist/declarations/src/@components/info-box/info-box.d.ts +7 -0
- package/dist/declarations/src/@components/upload-separator/index.d.ts +1 -0
- package/dist/declarations/src/@components/upload-separator/upload-separator.d.ts +12 -0
- package/dist/declarations/src/@components/upload-settings/index.d.ts +1 -0
- package/dist/declarations/src/@components/upload-settings/upload-settings.d.ts +11 -0
- package/dist/declarations/src/@components/uploading-modal/index.d.ts +1 -0
- package/dist/declarations/src/@components/uploading-modal/uploading-modal.d.ts +12 -0
- package/dist/declarations/src/@constants/delimiters.d.ts +8 -0
- package/dist/declarations/src/@constants/import-tags.d.ts +7 -0
- package/dist/declarations/src/@constants/index.d.ts +4 -0
- package/dist/declarations/src/@constants/resource-links.d.ts +10 -0
- package/dist/declarations/src/@constants/upload-limits.d.ts +10 -0
- package/dist/declarations/src/@errors/http-error.d.ts +6 -0
- package/dist/declarations/src/@errors/index.d.ts +8 -0
- package/dist/declarations/src/@errors/invalid-response-error.d.ts +3 -0
- package/dist/declarations/src/@errors/no-resources-to-export-error.d.ts +3 -0
- package/dist/declarations/src/@errors/project-key-not-available-error.d.ts +3 -0
- package/dist/declarations/src/@errors/query-predicate-error.d.ts +4 -0
- package/dist/declarations/src/@errors/unexpected-column-error.d.ts +3 -0
- package/dist/declarations/src/@errors/unexpected-operation-state-error.d.ts +4 -0
- package/dist/declarations/src/@errors/unexpected-resource-type-error.d.ts +3 -0
- package/dist/declarations/src/@hooks/index.d.ts +5 -0
- package/dist/declarations/src/@hooks/use-fetch-export-operations.d.ts +15 -0
- package/dist/declarations/src/@hooks/use-fetch-import-container-details.d.ts +15 -0
- package/dist/declarations/src/@hooks/use-fetch-import-operations.d.ts +16 -0
- package/dist/declarations/src/@hooks/use-fetch-import-summaries.d.ts +20 -0
- package/dist/declarations/src/@hooks/use-import-container-upload.d.ts +18 -0
- package/dist/declarations/src/@types/api.d.ts +13 -0
- package/dist/declarations/src/@types/basic-error-data-type.d.ts +5 -0
- package/dist/declarations/src/@types/export-operation.d.ts +95 -0
- package/dist/declarations/src/@types/file-upload.d.ts +63 -0
- package/dist/declarations/src/@types/import-container.d.ts +53 -0
- package/dist/declarations/src/@types/import-operation.d.ts +13 -0
- package/dist/declarations/src/@types/import-states.d.ts +9 -0
- package/dist/declarations/src/@types/import-summary.d.ts +15 -0
- package/dist/declarations/src/@types/index.d.ts +9 -0
- package/dist/declarations/src/@types/shared.d.ts +7 -0
- package/dist/declarations/src/@utils/error-mapping.d.ts +19 -0
- package/dist/declarations/src/@utils/file-upload.d.ts +46 -0
- package/dist/declarations/src/@utils/form.d.ts +1 -0
- package/dist/declarations/src/@utils/format.d.ts +5 -0
- package/dist/declarations/src/@utils/import-container.d.ts +8 -0
- package/dist/declarations/src/@utils/index.d.ts +6 -0
- package/dist/declarations/src/@utils/url.d.ts +6 -0
- package/dist/declarations/src/index.d.ts +26 -0
- package/index.js +1 -0
- package/jest.test.config.js +11 -0
- package/package.json +63 -0
- package/src/@api/export-operations.ts +26 -0
- package/src/@api/fetcher.spec.ts +51 -0
- package/src/@api/fetcher.ts +127 -0
- package/src/@api/file-upload.spec.ts +83 -0
- package/src/@api/file-upload.ts +46 -0
- package/src/@api/import-containers.ts +256 -0
- package/src/@api/import-operations.ts +33 -0
- package/src/@api/index.ts +8 -0
- package/src/@api/process-file.spec.ts +74 -0
- package/src/@api/process-file.ts +53 -0
- package/src/@api/test-fixtures.ts +772 -0
- package/src/@api/urls.ts +118 -0
- package/src/@components/file-drop-area/active-drag-drop-area.tsx +33 -0
- package/src/@components/file-drop-area/disabled-drop-area.tsx +17 -0
- package/src/@components/file-drop-area/drop-area-wrapper.tsx +38 -0
- package/src/@components/file-drop-area/enabled-drop-area.tsx +27 -0
- package/src/@components/file-drop-area/file-drop-area.tsx +74 -0
- package/src/@components/file-drop-area/file-dropped-area.tsx +29 -0
- package/src/@components/file-drop-area/index.ts +7 -0
- package/src/@components/file-drop-area/styles.ts +67 -0
- package/src/@components/icons/file-icon.tsx +30 -0
- package/src/@components/icons/index.ts +2 -0
- package/src/@components/icons/lock-icon.tsx +34 -0
- package/src/@components/index.ts +6 -0
- package/src/@components/info-box/index.ts +1 -0
- package/src/@components/info-box/info-box.tsx +23 -0
- package/src/@components/upload-separator/index.ts +1 -0
- package/src/@components/upload-separator/upload-separator.tsx +61 -0
- package/src/@components/upload-settings/index.ts +1 -0
- package/src/@components/upload-settings/upload-settings.tsx +36 -0
- package/src/@components/uploading-modal/index.ts +1 -0
- package/src/@components/uploading-modal/uploading-modal.tsx +64 -0
- package/src/@constants/delimiters.ts +14 -0
- package/src/@constants/import-tags.ts +9 -0
- package/src/@constants/index.ts +4 -0
- package/src/@constants/resource-links.ts +61 -0
- package/src/@constants/upload-limits.ts +11 -0
- package/src/@errors/http-error.ts +17 -0
- package/src/@errors/index.ts +8 -0
- package/src/@errors/invalid-response-error.ts +6 -0
- package/src/@errors/no-resources-to-export-error.ts +6 -0
- package/src/@errors/project-key-not-available-error.ts +6 -0
- package/src/@errors/query-predicate-error.ts +10 -0
- package/src/@errors/unexpected-column-error.ts +6 -0
- package/src/@errors/unexpected-operation-state-error.ts +8 -0
- package/src/@errors/unexpected-resource-type-error.ts +6 -0
- package/src/@hooks/index.ts +5 -0
- package/src/@hooks/messages.ts +11 -0
- package/src/@hooks/use-fetch-export-operations.ts +34 -0
- package/src/@hooks/use-fetch-import-container-details.ts +31 -0
- package/src/@hooks/use-fetch-import-operations.ts +42 -0
- package/src/@hooks/use-fetch-import-summaries.ts +47 -0
- package/src/@hooks/use-fetch.spec.ts +76 -0
- package/src/@hooks/use-fetch.ts +80 -0
- package/src/@hooks/use-import-container-upload.spec.ts +294 -0
- package/src/@hooks/use-import-container-upload.ts +126 -0
- package/src/@types/api.ts +14 -0
- package/src/@types/basic-error-data-type.ts +5 -0
- package/src/@types/export-operation.ts +144 -0
- package/src/@types/file-upload.ts +81 -0
- package/src/@types/import-container.ts +104 -0
- package/src/@types/import-operation.ts +31 -0
- package/src/@types/import-states.ts +9 -0
- package/src/@types/import-summary.ts +22 -0
- package/src/@types/index.ts +9 -0
- package/src/@types/shared.ts +52 -0
- package/src/@utils/error-mapping.spec.ts +126 -0
- package/src/@utils/error-mapping.ts +39 -0
- package/src/@utils/file-upload.spec.ts +151 -0
- package/src/@utils/file-upload.ts +150 -0
- package/src/@utils/form.ts +20 -0
- package/src/@utils/format.spec.ts +62 -0
- package/src/@utils/format.ts +53 -0
- package/src/@utils/import-container.spec.ts +26 -0
- package/src/@utils/import-container.ts +34 -0
- package/src/@utils/index.ts +6 -0
- package/src/@utils/url.spec.ts +75 -0
- package/src/@utils/url.ts +18 -0
- package/src/index.ts +27 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const mapFormikErrors = (
|
|
2
|
+
error: string | string[] | undefined | Record<string, boolean>
|
|
3
|
+
): Record<string, boolean> => {
|
|
4
|
+
if (typeof error === 'string') {
|
|
5
|
+
return { [error]: true }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (Array.isArray(error)) {
|
|
9
|
+
return error.reduce(
|
|
10
|
+
(errorAggregator, currentError) => ({
|
|
11
|
+
...errorAggregator,
|
|
12
|
+
[currentError]: true,
|
|
13
|
+
}),
|
|
14
|
+
{}
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!error) return {}
|
|
19
|
+
return error
|
|
20
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { formatErrorCode, appendCsvOrJsonExtensionIfAbsent } from './format'
|
|
2
|
+
|
|
3
|
+
describe('formatErrorCode', () => {
|
|
4
|
+
it('should format camel case correctly', () => {
|
|
5
|
+
expect(formatErrorCode('ReferencedResourceNotFound')).toBe(
|
|
6
|
+
'Referenced resource not found'
|
|
7
|
+
)
|
|
8
|
+
})
|
|
9
|
+
it('should handle consecutive uppercase letters correctly', () => {
|
|
10
|
+
expect(formatErrorCode('InvalidJSONInput')).toBe('Invalid JSON input')
|
|
11
|
+
})
|
|
12
|
+
it('should handle single word correctly', () => {
|
|
13
|
+
expect(formatErrorCode('Error')).toBe('Error')
|
|
14
|
+
})
|
|
15
|
+
it('should handle already formatted string correctly', () => {
|
|
16
|
+
expect(formatErrorCode('Already formatted string')).toBe(
|
|
17
|
+
'Already formatted string'
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
it('should return the original code if formatting fails', () => {
|
|
21
|
+
const invalidCode = null as any
|
|
22
|
+
expect(formatErrorCode(invalidCode)).toBe(invalidCode)
|
|
23
|
+
})
|
|
24
|
+
it('should handle empty string correctly', () => {
|
|
25
|
+
expect(formatErrorCode('')).toBe('')
|
|
26
|
+
})
|
|
27
|
+
it('should uppercase specific words correctly', () => {
|
|
28
|
+
expect(formatErrorCode('InvalidAPIResponse')).toBe('Invalid API response')
|
|
29
|
+
expect(formatErrorCode('HttpRequestFailed')).toBe('HTTP request failed')
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('appendCsvOrJsonExtensionIfAbsent', () => {
|
|
34
|
+
it('should append .csv if no extension is present', () => {
|
|
35
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file', 'csv')).toBe('file.csv')
|
|
36
|
+
})
|
|
37
|
+
it('should append .json if no extension is present', () => {
|
|
38
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file', 'json')).toBe('file.json')
|
|
39
|
+
})
|
|
40
|
+
it('should not append .csv if .csv is already present', () => {
|
|
41
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file.csv', 'csv')).toBe('file.csv')
|
|
42
|
+
})
|
|
43
|
+
it('should not append .json if .json is already present', () => {
|
|
44
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file.json', 'json')).toBe(
|
|
45
|
+
'file.json'
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
it('should be case insensitive to extensions', () => {
|
|
49
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file.JSON', 'json')).toBe(
|
|
50
|
+
'file.JSON'
|
|
51
|
+
)
|
|
52
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file.CSV', 'csv')).toBe('file.CSV')
|
|
53
|
+
})
|
|
54
|
+
it('should append .csv or .json extension if a different extension is present', () => {
|
|
55
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file.txt', 'csv')).toBe(
|
|
56
|
+
'file.txt.csv'
|
|
57
|
+
)
|
|
58
|
+
expect(appendCsvOrJsonExtensionIfAbsent('file.txt', 'json')).toBe(
|
|
59
|
+
'file.txt.json'
|
|
60
|
+
)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export function formatErrorCode(code: string): string {
|
|
2
|
+
try {
|
|
3
|
+
const formattedCode = code
|
|
4
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
5
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1 $2')
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
let result = formattedCode.charAt(0).toUpperCase() + formattedCode.slice(1)
|
|
8
|
+
|
|
9
|
+
const specialWords = ['json', 'api', 'http']
|
|
10
|
+
specialWords.forEach((word) => {
|
|
11
|
+
const regex = new RegExp(`\\b${word}\\b`, 'gi')
|
|
12
|
+
result = result.replace(regex, word.toUpperCase())
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
return result
|
|
16
|
+
} catch (error) {
|
|
17
|
+
return code
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function extractErrorDescriptionFromValidationMessage(
|
|
22
|
+
message: string
|
|
23
|
+
): string | undefined {
|
|
24
|
+
return message.split('"').pop()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function formatKeys(
|
|
28
|
+
obj: Record<string, unknown>,
|
|
29
|
+
conjunction: string = 'and'
|
|
30
|
+
): string {
|
|
31
|
+
if (typeof obj !== 'object' || obj === null) return ''
|
|
32
|
+
const keys = Object.keys(obj).map((key) =>
|
|
33
|
+
key.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase()
|
|
34
|
+
)
|
|
35
|
+
if (keys.length === 0) return ''
|
|
36
|
+
if (keys.length === 1) return keys[0]
|
|
37
|
+
return `${keys.slice(0, -1).join(', ')} ${conjunction} ${
|
|
38
|
+
keys[keys.length - 1]
|
|
39
|
+
}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function appendCsvOrJsonExtensionIfAbsent(
|
|
43
|
+
fileName: string,
|
|
44
|
+
fileFormat: 'csv' | 'json'
|
|
45
|
+
): string {
|
|
46
|
+
const extensionRegex = /\.(csv|json)$/i
|
|
47
|
+
if (!extensionRegex.test(fileName)) return `${fileName}.${fileFormat}`
|
|
48
|
+
return fileName
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function convertFileSizeToKB(sizeInBytes: number): number {
|
|
52
|
+
return sizeInBytes / 1000
|
|
53
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decodeFileNameFromImportContainerKey,
|
|
3
|
+
encodeFileNameWithTimestampToContainerKey,
|
|
4
|
+
} from './import-container'
|
|
5
|
+
|
|
6
|
+
describe('decodeFileNameFromImportContainerKey', () => {
|
|
7
|
+
it('should decode the file name from a encoded container key', () => {
|
|
8
|
+
const fileName = 'categories.csv'
|
|
9
|
+
const encodedKey =
|
|
10
|
+
'eyJ0aW1lc3RhbXAiOiAxNzA1MDExMTQ5MTgxLCAiZmlsZU5hbWUiOiAiY2F0ZWdvcmllcy5jc3YifQ'
|
|
11
|
+
expect(decodeFileNameFromImportContainerKey(encodedKey)).toBe(fileName)
|
|
12
|
+
})
|
|
13
|
+
it('should return empty string if decoding fails', () => {
|
|
14
|
+
const invalidKey = 'notBase64Strng'
|
|
15
|
+
expect(decodeFileNameFromImportContainerKey(invalidKey)).toBe('')
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
describe('encodeFileNameWithTimestampToContainerKey', () => {
|
|
19
|
+
it('should encode the file name and time stamp into a container key', () => {
|
|
20
|
+
const fileName = 'products.csv'
|
|
21
|
+
const encodedKey = encodeFileNameWithTimestampToContainerKey(fileName)
|
|
22
|
+
const decoded = JSON.parse(atob(encodedKey))
|
|
23
|
+
expect(decoded.fileName).toBe(fileName)
|
|
24
|
+
expect(typeof decoded.timestamp).toBe('number')
|
|
25
|
+
})
|
|
26
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface ImportInfo {
|
|
2
|
+
fileName: string
|
|
3
|
+
timestamp: number
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const encodeFileNameWithTimestampToContainerKey = (fileName: string) => {
|
|
7
|
+
return btoa(
|
|
8
|
+
JSON.stringify({
|
|
9
|
+
timestamp: new Date().getTime(),
|
|
10
|
+
fileName,
|
|
11
|
+
})
|
|
12
|
+
).replace(/=+$/g, '')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check if an import container is a file upload import
|
|
17
|
+
* @param tags - Array of tags from the import container
|
|
18
|
+
* @returns True if the tags indicate this is a file upload import
|
|
19
|
+
*/
|
|
20
|
+
export const checkIfFileUploadImport = (tags?: string[]): boolean => {
|
|
21
|
+
return tags?.some((tag) => tag.startsWith('source:file-upload')) ?? false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const decodeFileNameFromImportContainerKey = (
|
|
25
|
+
importContainerKey: string
|
|
26
|
+
) => {
|
|
27
|
+
try {
|
|
28
|
+
const decodedImportContainerKey = atob(importContainerKey)
|
|
29
|
+
const importInfo: ImportInfo = JSON.parse(decodedImportContainerKey)
|
|
30
|
+
return importInfo.fileName
|
|
31
|
+
} catch {
|
|
32
|
+
return ''
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { formatQueryString } from './url'
|
|
2
|
+
|
|
3
|
+
describe('formatQueryString', () => {
|
|
4
|
+
it('should return empty string with no params', () => {
|
|
5
|
+
const queryParam: Record<string, unknown> = {}
|
|
6
|
+
expect(formatQueryString(queryParam)).toEqual('')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it('should format multiple params', () => {
|
|
10
|
+
const queryParam: Record<string, unknown> = {
|
|
11
|
+
limit: 20,
|
|
12
|
+
offset: 10,
|
|
13
|
+
}
|
|
14
|
+
expect(formatQueryString(queryParam)).toEqual('?limit=20&offset=10')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('should handle offset zero', () => {
|
|
18
|
+
const queryParam: Record<string, unknown> = {
|
|
19
|
+
limit: 20,
|
|
20
|
+
offset: 0,
|
|
21
|
+
}
|
|
22
|
+
expect(formatQueryString(queryParam)).toEqual('?limit=20&offset=0')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should handle array values', () => {
|
|
26
|
+
const queryParam: Record<string, unknown> = {
|
|
27
|
+
state: ['imported', 'validationFailed'],
|
|
28
|
+
}
|
|
29
|
+
expect(formatQueryString(queryParam)).toEqual(
|
|
30
|
+
'?state=imported&state=validationFailed'
|
|
31
|
+
)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should handle undefined values', () => {
|
|
35
|
+
const queryParam: Record<string, unknown> = {
|
|
36
|
+
state: undefined,
|
|
37
|
+
}
|
|
38
|
+
expect(formatQueryString(queryParam)).toEqual('')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should handle null values', () => {
|
|
42
|
+
const queryParam: Record<string, unknown> = {
|
|
43
|
+
state: null,
|
|
44
|
+
}
|
|
45
|
+
expect(formatQueryString(queryParam)).toEqual('')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should handle boolean values', () => {
|
|
49
|
+
const queryParam: Record<string, unknown> = {
|
|
50
|
+
debug: true,
|
|
51
|
+
verbose: false,
|
|
52
|
+
}
|
|
53
|
+
expect(formatQueryString(queryParam)).toEqual('?debug=true&verbose=false')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should handle numeric values', () => {
|
|
57
|
+
const queryParam: Record<string, unknown> = {
|
|
58
|
+
limit: 100,
|
|
59
|
+
offset: 50,
|
|
60
|
+
}
|
|
61
|
+
expect(formatQueryString(queryParam)).toEqual('?limit=100&offset=50')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('should handle mixed types', () => {
|
|
65
|
+
const queryParam: Record<string, unknown> = {
|
|
66
|
+
limit: 20,
|
|
67
|
+
offset: 10,
|
|
68
|
+
state: ['imported', 'validationFailed'],
|
|
69
|
+
debug: true,
|
|
70
|
+
}
|
|
71
|
+
expect(formatQueryString(queryParam)).toEqual(
|
|
72
|
+
'?limit=20&offset=10&state=imported&state=validationFailed&debug=true'
|
|
73
|
+
)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats an object into a URL query string
|
|
3
|
+
* @param queryParams - Object containing query parameters
|
|
4
|
+
* @returns Formatted query string with leading '?' or empty string
|
|
5
|
+
*/
|
|
6
|
+
export function formatQueryString(queryParams: Record<string, unknown> = {}) {
|
|
7
|
+
const queryString = new URLSearchParams()
|
|
8
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
9
|
+
if (value !== undefined && value !== null) {
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
value.forEach((v) => queryString.append(key, String(v)))
|
|
12
|
+
} else {
|
|
13
|
+
queryString.append(key, String(value))
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return queryString.toString() ? `?${queryString.toString()}` : ''
|
|
18
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared package for operations
|
|
3
|
+
*
|
|
4
|
+
* This package provides shared functionality for import/export operations across:
|
|
5
|
+
* - application-operations
|
|
6
|
+
* - import-resources-modal
|
|
7
|
+
* - export-resources-modal
|
|
8
|
+
* - delete-resources-modal
|
|
9
|
+
* - unpublish-products-modal
|
|
10
|
+
*
|
|
11
|
+
* Public API includes:
|
|
12
|
+
* - Hooks: useImportContainerUpload, useFetch*, etc.
|
|
13
|
+
* - Components: FileDropArea, UploadingModal, UploadSettings, etc.
|
|
14
|
+
* - Utils: File validation, error mapping, formatting, etc.
|
|
15
|
+
* - Constants: Delimiters, upload limits, resource links, etc.
|
|
16
|
+
* - Types: All TypeScript types and interfaces
|
|
17
|
+
* - Errors: Custom error classes
|
|
18
|
+
* - API: Functions for interacting with import/export APIs
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export * from './@api'
|
|
22
|
+
export * from './@components'
|
|
23
|
+
export * from './@constants'
|
|
24
|
+
export * from './@errors'
|
|
25
|
+
export * from './@hooks'
|
|
26
|
+
export * from './@types'
|
|
27
|
+
export * from './@utils'
|