/** * Created by Samuel Gratzl on 29.09.2016. */ import {BaseUtils} from 'phovea_core'; import * as d3 from 'd3'; import {ITypeDefinition, ValueTypeEditor, ValueTypeUtils} from '../valuetype/valuetypes'; import {IDataDescription} from 'phovea_core'; import {UserSession} from 'phovea_core'; import {I18nextManager} from 'phovea_core'; export interface IColumnDefinition { name: string; column: string | number; value: ITypeDefinition; } export class ImportUtils { static commonFields(name: string) { const prefix = 'i' + BaseUtils.randomId(3); return `
`; } static extractCommonFields($root: d3.Selection) { return { name: $root.select('input[name="name"]').property('value'), description: $root.select('textarea[name="desc"]').property('value') }; } static async importTable(editors: ValueTypeEditor[], $root: d3.Selection, header: string[], data: string[][], name: string) { $root.html(`${ImportUtils.commonFields(name)}
${I18nextManager.getInstance().i18n.t('phovea:importer.column')} ${I18nextManager.getInstance().i18n.t('phovea:importer.type')}
`); const configPromises = header.map((name, i) => { return ValueTypeUtils.guessValueType(editors, name, i, data, (row) => row[i]); }); const guessedEditors = await Promise.all(configPromises); const config = await Promise.all(header.map(async (name, i) => { const value = await guessedEditors[i].guessOptions({type: null}, data, (col) => col[i]); const markup = await ValueTypeUtils.createTypeEditor(editors, guessedEditors[i], value); return { column: i, name, color: '#DDDDDD', value, editor: guessedEditors[i], markup }; })); const $rows = $root.select('tbody').selectAll('tr').data(config); function getCellMarkup(d) { return ` ${d.markup} `; } const $rowsEnter = $rows.enter().append('tr') .html(getCellMarkup); $rowsEnter.select('input').on('change', function (d) { d.name = this.value; }); $rowsEnter.select('select').on('change', ValueTypeUtils.updateType(editors)); $rowsEnter.select('button').on('click', (d) => { d.editor.edit(d.value); }); const common = ImportUtils.extractCommonFields($root); return () => ({data, desc: ImportUtils.toTableDataDescription(config, data, common)}); } static toTableDataDescription(config: IColumnDefinition[], data: any[], common: {name: string, description: string}) { //derive all configs config = config.filter((c) => (c).editor != null); config.forEach((d) => { const editor = (d).editor; editor.parse(d.value, data, (row, value?) => { if (typeof value !== 'undefined') { return row[d.column] = value; } return row[d.column]; }); }); //generate config let idProperty = config.filter((d) => d.value.type === 'idType')[0]; if (!idProperty) { //create an artificial one idProperty = {value: {type: 'idType', idType: 'Custom'}, name: 'IDType', column: '_index'}; data.forEach((d, i) => d._index = i); } const columns = config.filter((c) => c !== idProperty).map((c) => { const r: IColumnDefinition = BaseUtils.mixin({}, c); delete (r).editor; return r; }); const desc: IDataDescription = { type: 'table', id: BaseUtils.fixId(common.name + BaseUtils.randomId(2)), name: common.name, description: common.description, creator: UserSession.getInstance().currentUserNameOrAnonymous(), ts: Date.now(), fqname: 'upload/' + common.name, size: [data.length, columns.length], idtype: (idProperty).value.idType, columns, idcolumn: idProperty.column }; return desc; } static async importMatrix(editors: ValueTypeEditor[], $root: d3.Selection, header: string[], data: string[][], name: string) { const prefix = 'a' + BaseUtils.randomId(3); const rows = header.slice(1), cols = data.map((d) => d.shift()); const dataRange = d3.range(rows.length * cols.length); function byIndex(i, v?) { const m = i % cols.length; if (v !== undefined) { return data[(i - m) / cols.length][m] = v; } else { return data[(i - m) / cols.length][m]; } } const editor = await ValueTypeUtils.guessValueType(editors, 'value', -1, dataRange, byIndex); const configs = [{ column: -1, name: I18nextManager.getInstance().i18n.t('phovea:importer.rowName'), value: { type: 'idType' }, editor: editors.filter((e) => e.id === 'idType')[0] }, { column: -1, name: I18nextManager.getInstance().i18n.t('phovea:importer.columnName'), value: { type: 'idType' }, editor: editors.filter((e) => e.id === 'idType')[0] }, { column: -1, name: I18nextManager.getInstance().i18n.t('phovea:importer.value'), value: { type: null }, editor }]; const $rows = $root.html(ImportUtils.commonFields(name)).selectAll('div.field').data(configs); $rows.enter().append('div').classed('form-group', true).html((d, i) => `
`); $rows.select('select').on('change', ValueTypeUtils.updateType(editors, false)); $rows.select('button').on('click', (d, i) => { if (i < 2) { d.editor.guessOptions(d.value, i === 0 ? rows : cols, BaseUtils.identity); } else { d.editor.guessOptions(d.value, dataRange, byIndex); } d.editor.edit(d.value); }); //parse data //TODO set rows and cols configs[0].editor.parse(configs[0].value, rows, BaseUtils.identity); configs[1].editor.parse(configs[1].value, cols, BaseUtils.identity); configs[2].editor.parse(configs[2].value, dataRange, byIndex); const common = ImportUtils.extractCommonFields($root); const desc: IDataDescription = { type: 'matrix', id: BaseUtils.fixId(common.name + BaseUtils.randomId(3)), name: common.name, fqname: 'upload/' + common.name, creator: UserSession.getInstance().currentUserNameOrAnonymous(), ts: Date.now(), description: common.description, size: [rows.length, cols.length], rowtype: (configs[0]).value.idType, coltype: (configs[1]).value.idType, value: configs[1].value }; return () => ({rows, cols, data, desc}); } }