diff --git a/assets/js/components/ImportDialog.js b/assets/js/components/ImportDialog.js index 7402ac38..d6471f9f 100644 --- a/assets/js/components/ImportDialog.js +++ b/assets/js/components/ImportDialog.js @@ -22,18 +22,20 @@ import SheetClip from 'sheetclip' const sheetclip = new SheetClip() -const columnNames = { - name: ['name', 'full name'], - email: ['email', 'e-mail', 'email address'], - phone: ['phone', 'phone number'], - address: ['address', 'street address'], - state: ['state'], +function fetchValidFields() { + return fetch('/api/people/', {method: 'OPTIONS'}) + .then(resp => resp.json()) + .then(resp => Object.entries(resp.actions.POST) + .filter(([_fieldName, fieldProps]) => fieldProps.read_only == false) + .map(([fieldName, fieldProps]) => [fieldName, [fieldName, ...fieldProps.aliases]]) + .reduce((prev, next) => ({...prev, [next[0]]: next[1]}), {}) + ) } -function guessHeaderMap(columns) { +function guessHeaderMap(columns, knownColumns) { return _.fromPairs(_.map(columns, c => { const normalized = c.toLowerCase() - const commonName = _.findKey(columnNames, alternatives => alternatives.indexOf(normalized) >= 0) + const commonName = _.findKey(knownColumns, alternatives => alternatives.indexOf(normalized) >= 0) if (commonName) { return [c, commonName] } else { @@ -48,7 +50,7 @@ function mapRows(rows, headerMap, tags) { return _.map(compactRows, row => { - const mappedObject = _.mapKeys(row, (_v, k) => _.get(headerMap, k, k)) + const mappedObject = _.pickBy(_.mapKeys(row, (_v, k) => _.get(headerMap, k, k)), v => v != undefined) return { ...mappedObject, @@ -59,17 +61,17 @@ function mapRows(rows, headerMap, tags) { } -function parsePaste({input}) { +function parsePaste({input}, knownHeaders) { const sheet = sheetclip.parse(input) const headers = _.head(sheet) - const rows = _.tail(sheet) + const rows = _.tail(sheet).map(row => row.map(column => column == '' ? undefined : column)) const tagKeys = _.filter(headers, key => key.startsWith('tag:')) const tags = _.map(tagKeys, key => { return key.substr(4) }) - const headerMap = guessHeaderMap(_.difference(headers, tagKeys)) + const headerMap = guessHeaderMap(_.difference(headers, tagKeys), knownHeaders) const jsonRows = _.map(rows, row => _.zipObject(headers, row)) @@ -86,12 +88,18 @@ class ImportDialog extends React.Component { this.state = { stage: 0, parsed: {headerMap: {}}, - mapped: [] + mapped: [], + validFields: {} } this.next = this.next.bind(this) this.previous = this.previous.bind(this) } + componentDidMount() { + fetchValidFields() + .then(fields => this.setState({validFields: fields})) + } + reset() { this.setState({stage: 0}) } @@ -99,7 +107,7 @@ class ImportDialog extends React.Component { next() { switch(this.state.stage) { case 0: - this.setState({parsed: parsePaste(this.pasteForm.formContext.formState.values), stage: 1}) + this.setState({parsed: parsePaste(this.pasteForm.formContext.formState.values, this.state.validFields), stage: 1}) break case 1: this.setState({stage: 2, mapped: mapRows(this.state.parsed.rows, this.state.parsed.headerMap, this.state.parsed.tags)}) @@ -134,11 +142,13 @@ class ImportDialog extends React.Component { What headers can I use?
All headers are case insensitive. The following lists acceptable values:
-| Column | Aliases |
|---|---|
| {k} | {v.join(', ')} |
| Tags | To tag people, include a column that starts with "tag:". eg "tag:Came to meeting" tags each person in the spreadsheet with "Came to meeting" |
The following data will be imported:
| Name | Phone number | Street address | State | |
|---|---|---|---|---|
| {header} | )} +||||
| {row.name} {_.map(row.tags, t => | {row.email} | -{row.phone} | {row.address} | {row.state} | + {this.state.mapped.map((row, idx) => ( +
| {header == 'tags' ? row[header].map(tag => | )}