Skip to content

Commit

Permalink
feat: implement array property upload functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
maxpeterson committed Jun 16, 2021
1 parent dd857f7 commit 10e7c8c
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 150 deletions.
6 changes: 3 additions & 3 deletions src/features/upload-file/components/edit.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import React, { FC, useState, useEffect } from 'react'
import { EditPropertyProps, flat } from 'admin-bro'
import { DropZone, FormGroup, Label, DropZoneItem } from '@admin-bro/design-system'
import PropertyCustom from '../types/property-custom.type'
import buildCustom from '../utils/build-custom'

const Edit: FC<EditPropertyProps> = ({ property, record, onChange }) => {
const { params } = record
const { custom } = property as unknown as { custom: PropertyCustom }
const custom = buildCustom(property)

const path = flat.get(params, custom.filePathProperty)
const key = flat.get(params, custom.keyProperty)
const file = flat.get(params, custom.fileProperty)

const [originalKey, setOriginalKey] = useState(key)
const [filesToUpload, setFilesToUpload] = useState<Array<File>>([])
const [filesToUpload, setFilesToUpload] = useState<Array<File>>(file || [])

useEffect(() => {
// it means means that someone hit save and new file has been uploaded
Expand Down
3 changes: 2 additions & 1 deletion src/features/upload-file/components/file.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Icon, Button, Box } from '@admin-bro/design-system'
import { ShowPropertyProps, flat } from 'admin-bro'
import { ImageMimeTypes, AudioMimeTypes } from '../types/mime-types.type'
import PropertyCustom from '../types/property-custom.type'
import buildCustom from '../utils/build-custom'

type Props = ShowPropertyProps & {
width?: number | string;
Expand Down Expand Up @@ -47,7 +48,7 @@ const SingleFile: FC<SingleFileProps> = (props) => {
}

const File: FC<Props> = ({ width, record, property }) => {
const { custom } = property as unknown as { custom: PropertyCustom }
const custom = buildCustom(property)

const path = flat.get(record?.params, custom.filePathProperty)

Expand Down
30 changes: 26 additions & 4 deletions src/features/upload-file/factories/strip-payload-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,40 @@ export const stripPayloadFactory = (
request: ActionRequest,
context: ActionContext,
): Promise<ActionRequest> => {
const { properties } = uploadOptionsWithDefault
const { properties, parentArray } = uploadOptionsWithDefault

if (request?.payload) {
let data: ContextNamespace = context[CONTEXT_NAMESPACE] || {}

if (parentArray) {
const parent = flat.get(request.payload, parentArray)
if (parent) {
for (let index = 0; index < parent.length; index += 1) {
data = {
...data,
...[properties.file, properties.filesToDelete].reduce((memo, prop) => {
const fullProp = [parentArray, index, prop].join(flat.DELIMITER)
return {
...memo,
[fullProp]: flat.get(request.payload, fullProp),
}
}, {}),
}
}
}
} else {
data = {
...data,
[properties.file]: flat.get(request.payload, properties.file),
[properties.filesToDelete]: flat.get(request.payload, properties.filesToDelete),
}
}

data = {
...data,
[properties.file]: flat.get(request.payload, properties.file),
[properties.filesToDelete]: flat.get(request.payload, properties.filesToDelete),
__invocations: [
...(data.__invocations || []),
{ properties },
{ properties, parentArray },
],
}

Expand Down
19 changes: 13 additions & 6 deletions src/features/upload-file/factories/update-record-factory.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ describe('updateRecordFactory', () => {
recordStub = createStubInstance(BaseRecord, {
id: sinon.stub<any, string>().returns('1'),
isValid: sinon.stub<any, boolean>().returns(true),
update: sinon.stub<any, Promise<BaseRecord>>().returnsThis(),
save: sinon.stub<[], Promise<BaseRecord>>().returnsThis(),
storeParams: sinon.stub<any, void>(),
})
recordStub.params = {}
})
Expand Down Expand Up @@ -92,13 +93,14 @@ describe('updateRecordFactory', () => {
it('updates all fields in the record', async () => {
await updateRecord(response, request, actionContext)

expect(recordStub.update).to.have.been.calledWith(sinon.match({
expect(recordStub.storeParams).to.have.been.calledWith(sinon.match({
[uploadOptions.properties.key]: expectedKey,
[uploadOptions.properties.bucket as string]: provider.bucket,
[uploadOptions.properties.size as string]: File.size.toString(),
[uploadOptions.properties.mimeType as string]: File.type,
[uploadOptions.properties.filename as string]: File.name,
}))
expect(recordStub.save).to.have.been.calledWith()
})

it('does not delete any old file if there were not file before', async () => {
Expand Down Expand Up @@ -138,13 +140,14 @@ describe('updateRecordFactory', () => {

expect(provider.delete).to.have.been.calledWith(expectedKey, storedBucket)

expect(recordStub.update).to.have.been.calledWith(sinon.match({
expect(recordStub.storeParams).to.have.been.calledWith(sinon.match({
[uploadOptions.properties.key]: null,
[uploadOptions.properties.bucket as string]: null,
[uploadOptions.properties.size as string]: null,
[uploadOptions.properties.mimeType as string]: null,
[uploadOptions.properties.filename as string]: null,
}))
expect(recordStub.save).to.have.been.calledWith()
})
})

Expand Down Expand Up @@ -188,11 +191,12 @@ describe('updateRecordFactory', () => {
[`${uploadOptions.properties.filename}.${index}` as string]: Files[index].name,
})

expect(recordStub.update).to.have.been.calledWith(sinon.match({
expect(recordStub.storeParams).to.have.been.calledWith(sinon.match({
...values(0),
...values(1),
...values(2),
}))
expect(recordStub.save).to.have.been.calledWith()
})
})

Expand Down Expand Up @@ -226,19 +230,22 @@ describe('updateRecordFactory', () => {
},
record: new BaseRecord(oldParams, {} as BaseResource),
} as unknown as ActionContext
sinon.stub(BaseRecord.prototype, 'update')
sinon.stub(BaseRecord.prototype, 'save')
sinon.stub(BaseRecord.prototype, 'storeParams')
sinon.stub(BaseRecord.prototype, 'toJSON')

updateRecord = updateRecordFactory(uploadOptions, provider)
})

it('removes files from the database', async () => {
await updateRecord(response, request, actionContext)

expect(BaseRecord.prototype.update).to.have.been.calledWith({
expect(BaseRecord.prototype.storeParams).to.have.been.calledWith({
'media.key.0': 'key1',
'media.bucket.0': 'bucket1',
'media.type.0': 'mime1',
})
expect(BaseRecord.prototype.save).to.have.been.calledWith()
})

it('removes files from the adapter store', async () => {
Expand Down
Loading

0 comments on commit 10e7c8c

Please sign in to comment.