Commit f7251a4a authored by hh1966's avatar hh1966
Browse files

Add xlsx export for research plan tables

parent dd678d00
Pipeline #53371 failed with stage
......@@ -221,6 +221,31 @@ module Chemotion
end
end
end
desc "Export research plan table by id and field_id"
params do
requires :id, type: Integer, desc: "Research plan id"
requires :field_id, type: String, desc: "Field id"
end
route_param :id do
before do
error!('401 Unauthorized', 401) unless ElementPolicy.new(current_user, ResearchPlan.find(params[:id])).read?
end
get "export_table/:field_id" do
research_plan = ResearchPlan.find(params[:id])
field = research_plan.body.find {|field| field['id'] == params[:field_id]}
# return the response "as is" and set the content type and the filename
env['api.format'] = :binary
content_type "application/vnd.ms-excel"
header['Content-Disposition'] = "attachment; filename=\"Table.xlsx\""
export = Export::ExportResearchPlanTable.new
export.generate_sheet(field['value']['columns'], field['value']['rows'])
export.read
end
end
end
end
end
......@@ -150,6 +150,30 @@ export default class ResearchPlansFetcher {
return promise;
}
static exportTable(researchPlan, field) {
let file_name
const promise = fetch('/api/v1/research_plans/' + researchPlan.id + '/export_table/' + field.id, {
credentials: 'same-origin',
method: 'get',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
}).then((response) => {
if (response.ok) {
file_name = getFileName(response)
return response.blob()
} else {
throw Error(response.statusText);
}
}).then((blob) => {
downloadBlob(file_name, blob)
}).catch((errorMessage) => {
console.log(errorMessage);
});
return promise;
}
static fetchTableSchemas() {
return fetch('/api/v1/research_plans/table_schemas/', {
credentials: 'same-origin',
......@@ -158,15 +182,18 @@ export default class ResearchPlansFetcher {
Accept: 'application/json',
'Content-Type': 'application/json'
}
}).then(response => {
}).then((response) => {
if (response.ok) {
return response.json()
file_name = getFileName(response)
return response.blob()
} else {
console.log(response)
throw Error(response.statusText);
}
}).then((blob) => {
downloadBlob(file_name, blob)
}).catch((errorMessage) => {
console.log(errorMessage)
})
console.log(errorMessage);
});
}
static createTableSchema(name, value) {
......
......@@ -199,6 +199,11 @@ export default class ResearchPlanDetails extends Component {
ResearchPlansFetcher.export(research_plan, html, exportFormat)
}
handleExportField(field) {
const { research_plan } = this.props
ResearchPlansFetcher.exportTable(research_plan, field)
}
// render functions
renderResearchPlanInfo(research_plan) {
......@@ -266,6 +271,7 @@ export default class ResearchPlanDetails extends Component {
onDrop={this.handleBodyDrop.bind(this)}
onAdd={this.handleBodyAdd.bind(this)}
onDelete={this.handleBodyDelete.bind(this)}
onExport={this.handleExportField.bind(this)}
update={update}
edit={edit}
ref={this.bodyRef} />
......
......@@ -9,7 +9,7 @@ import Field from './ResearchPlanDetailsField'
export default class ResearchPlanDetailsBody extends Component {
render() {
let { body, disabled, onChange, onDrop, onAdd, onDelete, update, edit } = this.props
let { body, disabled, onChange, onDrop, onAdd, onDelete, onExport, update, edit } = this.props
let fields = body.map((field, index) => {
return <Field key={field.id}
......@@ -17,6 +17,7 @@ export default class ResearchPlanDetailsBody extends Component {
onChange={onChange.bind(this)}
onDrop={onDrop.bind(this)}
onDelete={onDelete.bind(this)}
onExport={onExport.bind(this)}
update={update}
edit={edit} />
})
......@@ -55,5 +56,8 @@ ResearchPlanDetailsBody.propTypes = {
disabled: PropTypes.bool,
onChange: PropTypes.func,
onDrop: PropTypes.func,
update: PropTypes.bool
onDelete: PropTypes.func,
onExport: PropTypes.func,
update: PropTypes.bool,
edit: PropTypes.bool
}
......@@ -16,7 +16,7 @@ import ResearchPlanDetailsFieldReaction from './ResearchPlanDetailsFieldReaction
export default class ResearchPlanDetailsField extends Component {
render() {
let { field, index, disabled, onChange, onDrop, onDelete, update, edit } = this.props
let { field, index, disabled, onChange, onDrop, onDelete, onExport, update, edit } = this.props
let label, component
switch (field.type) {
......@@ -42,7 +42,8 @@ export default class ResearchPlanDetailsField extends Component {
label = 'Table'
component = <ResearchPlanDetailsFieldTable key={field.id}
field={field} index={index} disabled={disabled}
onChange={onChange.bind(this)} update={update} edit={edit} />
onChange={onChange.bind(this)} onExport={onExport}
update={update} edit={edit} />
break;
case 'sample':
label = 'Sample'
......@@ -99,5 +100,8 @@ ResearchPlanDetailsField.propTypes = {
disabled: PropTypes.bool,
onChange: PropTypes.func,
onDrop: PropTypes.func,
update: PropTypes.bool
onDelete: PropTypes.func,
onExport: PropTypes.func,
update: PropTypes.bool,
edit: PropTypes.bool
}
......@@ -291,7 +291,7 @@ export default class ResearchPlanDetailsFieldTable extends Component {
}
renderEdit() {
const { field } = this.props
const { field, onExport } = this.props
const { rows, columns } = field.value
const { columnNameModal, schemaModal } = this.state
const editorPortalTarget = document.getElementsByClassName('react-grid-Viewport')[0]
......@@ -336,7 +336,7 @@ export default class ResearchPlanDetailsFieldTable extends Component {
</Button>
</Col>
<Col xs={3} xsOffset={6}>
<Button bsSize="xsmall">
<Button bsSize="xsmall" onClick={() => onExport(field)}>
Export as Excel
</Button>
</Col>
......
require 'tempfile'
module Export
class ExportResearchPlanTable
def initialize
@xfile = Axlsx::Package.new
@file_extension = 'xlsx'
@xfile.workbook.styles.fonts.first.name = 'Calibri'
end
def generate_sheet(columns, rows)
@xfile.workbook.add_worksheet(:name => "Pie Chart") do |sheet|
sheet.add_row columns.map {|column| column['name']}
rows.each do |row|
sheet.add_row columns.map {|column| row[column['key']]}
end
end
end
def read
@xfile.to_stream.read
end
end
end
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment