Skip to content
This repository was archived by the owner on Aug 12, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/antd-locales/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ export default {
"query.actions.export": "Export",
"query.actions.import": "Import",
"query.actions.filter": "Add Filter",
"image.error.noStorage": "There is no imageStorage, please contact your development team.",
"file.error.limitSize": "The file is larger than the limit {limitSize}."
"file.error.noStorage": "There is no fileStorage, please contact your development team.",
"image.error.limitSize": "The image is larger than the limit {limitSize}."
"image.error.noStorage": "There is no imageStorage, please contact your development team.",
},
zh: {
"array.panel.delete.confirm": "您確定要刪除這個類別嗎?",
Expand Down Expand Up @@ -83,6 +85,8 @@ export default {
"query.actions.export": "匯出",
"query.actions.import": "匯入",
"query.actions.filter": "搜尋",
"file.error.limitSize": "找不到任何的 fileStorage,請聯絡您的工程團隊。",
"file.error.noStorage": "超過檔案大小限制 {limitSize}。"
"image.error.noStorage": "找不到任何的 imageStorage,請聯絡您的工程團隊。",
"image.error.limitSize": "超過圖片大小限制 {limitSize}。"
}
Expand Down
49 changes: 49 additions & 0 deletions packages/antd-object-file/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# @canner/antd-object-file

## API

### Props:

<table>
<thead>
<tr>
<th style="width: 100px;">name</th>
<th style="width: 50px;">type</th>
<th>default</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>String</td>
<th></th>
<td>Field id</td>
</tr>
<tr>
<td>value</td>
<td>String</td>
<th></th>
<td>Default value</td>
</tr>
<tr>
<td>uiParams</td>
<td>
<code>
{
filename: string,
service: string
}
</code>
</td>
<th></th>
<td>Setup file service configurations</td>
</tr>
<tr>
<td>onChange</td>
<td>(id: string, type: string, value: string) => void</td>
<th></th>
<td>Called when input is changed</td>
</tr>
</tbody>
</table>
24 changes: 24 additions & 0 deletions packages/antd-object-file/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@canner/antd-object-file",
"version": "0.5.30",
"description": "object file",
"main": "lib/index.js",
"scripts": {},
"keywords": [
"canner",
"cms",
"file"
],
"author": "canner",
"license": "ISC",
"peerDependencies": {
"react": "^0.14.0 || ^15.0.0 || ^16.0.0"
},
"canner": {
"cannerDataType": "file"
},
"publishConfig": {
"access": "public"
},
"gitHead": "6ad58dfd03c39ef5ee549d8a3910096e8728008e"
}
103 changes: 103 additions & 0 deletions packages/antd-object-file/src/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// @flow
import React from "react";
import { Alert, Button, Icon, Upload } from "antd";

type Props = {
label?: string,
multiple: boolean,
onChange: (value: Array<string> | string) => void,
onClose: (e: any) => void,
serviceConfig: any
};

type State = {
fileList: Array<any>,
error: ?Error
};

export default class FileComponent extends React.Component<Props, State> {
constructor(props: Props) {
super(props);

(this: any).uploadFile = this.uploadFile.bind(this);
this.state = {
error: null,
fileList: (this: any).props.defaultValue || []
};
}

onClose = (e: any) => {
this.setState(
{
fileList: [],
error: null
}
);
}

onError = (e: any) => {
this.setState({
fileList: [],
error: e
});
}

uploadFile(info: { file: any, fileList: Array<any> }) {
let fileList = [...info.fileList];

fileList = fileList.slice(-1);

if (info.file.status === "done") {
fileList = fileList
.map(file => {
if (file.response && file.response.data) {
file.url = file.response.data.link;
}

return file;
});

this.props.onChange(fileList);
}

this.setState({
fileList,
});
}

render() {
const { label = 'Upload', multiple, serviceConfig } = this.props;
const { error, fileList } = this.state;
const props = {
multiple,
...serviceConfig,
onChange: this.uploadFile,
};

if (error) {
return (
<React.Fragment>
<Alert
closable
message={error.message}
onClose={this.onClose}
showIcon
type="error"
/>
</React.Fragment>
);
}

return (
<Upload
{...props}
fileList={fileList}
onError={this.onError}
>
<Button type="primary">
<Icon type="upload" /> {label}
</Button>
</Upload>
);
}
}
102 changes: 102 additions & 0 deletions packages/antd-object-file/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// @flow
import React, { PureComponent } from "react";
import { Upload, Button, Icon } from "antd";
import { FormattedMessage, injectIntl } from "react-intl";
import { isArray } from "lodash";
import defaultMessage from '@canner/antd-locales';
import FileComponent from "./file";

// type
import type {ObjectDefaultProps} from 'types/ObjectDefaultProps';

type Props = ObjectDefaultProps & {
fileStorage: any,
intl: Object,
uiParams: {
filename?: string,
limitSize?: number
}
};

type CustomRequestArgs = {
onProgress: (event: { percent: number }) => void,
onError: (event: Error, body?: Object) => void,
onSuccess: (body: Object) => void,
data: Object,
filename: String,
file: File,
withCredentials: Boolean,
action: String,
headers: Object
};

function getFilePayloadByValue(value: Object) {
let obj = value;
if (isArray(value)) {
obj = value[0];
}

return {
contentType: obj.type,
name: obj.name,
size: obj.size,
url: obj.url,
};
}

@injectIntl
export default class File extends React.PureComponent<Props> {
onChange = (newValue: Array<string> | string) => {
const { uiParams: { filename }, value } = this.props;
const filePayload = getFilePayloadByValue(newValue);
if (filename) {
filePayload.name = filename
}

this.props.onChange(this.props.refId, "update", {...value, ...filePayload});
}

render() {
const {
fileStorage,
intl,
uiParams: { filename, limitSize },
value,
} = this.props;

let defaultValue = [];
if (value && value.url) {
defaultValue.push({ uid: value.url, ...value});
}

return (
<FileComponent
defaultValue={defaultValue}
multiple={false}
onChange={this.onChange}
serviceConfig={{
customRequest: (obj) => {
const { file, onError, onProgress, onSuccess } = obj;
if (!fileStorage) {
onError(new Error(intl.formatMessage({ id: 'file.error.noStorage' })));
return;
}

if (limitSize && file.size > limitSize) {
onError(new Error(intl.formatMessage(
{ id: 'file.error.limitSize' },
{ limitSize }
)));
return;
}

fileStorage
.upload(file, { filename: filename || file.name }, onProgress)
.then(({ link }) => onSuccess({ data: { link } }))
.catch(onError);
}
}}
/>
);
}
}
42 changes: 42 additions & 0 deletions stories/demos/object/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//@flow
import React from 'react';
import {Divider} from 'antd';
import File from 'packages/antd-object-file';
import ExamplePrimitiveValueWrapper from '../ExamplePrimitiveValueHoc';
import type {PrimitiveTypes} from '../types';
import RefId from 'canner-ref-id';

const defaultValue = {
contentType: "video/mp4",
name: "cool.mp4",
size: 1233,
url: "https://mp4.com/cool.mp4"
};

@ExamplePrimitiveValueWrapper(defaultValue)
class ImageDemo1 extends React.Component<PrimitiveTypes<string>> {
render() {
const { value, onChange } = this.props;
return (
<React.Fragment>
<Divider>Normal file with file</Divider>
<File
refId={new RefId("file")}
value={value}
uiParams={{service: 'firebase'}}
onChange={onChange}
/>
</React.Fragment>
)
}
}

export default class Demo extends React.Component<{}> {
render() {
return (
<React.Fragment>
<ImageDemo1/>
</React.Fragment>
);
}
}
4 changes: 3 additions & 1 deletion stories/index.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import OptionsDemo from './demos/object/options';
import MapDemo from './demos/object/map';
import VariantsDemo from './demos/object/variants';
import ImageDemo from './demos/object/image';
import FileDemo from './demos/object/file';
import EditorDemo from './demos/object/editor';
import SlateDemo from './demos/object/slate_editor';

Expand Down Expand Up @@ -105,13 +106,14 @@ storiesOf('Array Component/Table Route', module)
.addDecorator(CannerHelperContext)
.add('Basic', () => <TableRouteDemo/>)
.add('With Toolbar', () => <TableRouteWithToolbarDemo/>)

storiesOf('Object Component', module)
.addDecorator(CannerHelperContext)
.add('Options', () => <OptionsDemo/>)
.add('Map', () => <MapDemo/>)
.add('Variants', () => <VariantsDemo/>)
.add('Image', () => <ImageDemo/>)
.add('File', () => <FileDemo />)
.add('Editor', () => <EditorDemo/>)
.add('Slate', () => <SlateDemo/>)

Expand Down