mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
CE-881 - Initial checkin - saved report entity, meta-data, and process to generate.
This commit is contained in:
@ -0,0 +1,386 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.savedreports;
|
||||
|
||||
|
||||
import java.time.Instant;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DynamicDefaultValueBehavior;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.TablesPossibleValueSourceMetaDataProvider;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Entity bean for the saved report table
|
||||
*******************************************************************************/
|
||||
public class SavedReport extends QRecordEntity
|
||||
{
|
||||
public static final String TABLE_NAME = "savedReport";
|
||||
|
||||
@QField(isEditable = false)
|
||||
private Integer id;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private Instant createDate;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private Instant modifyDate;
|
||||
|
||||
@QField(isRequired = true, maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
|
||||
private String label;
|
||||
|
||||
@QField(possibleValueSourceName = TablesPossibleValueSourceMetaDataProvider.NAME, maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR)
|
||||
private String tableName; // todo - qqqTableId... ?
|
||||
|
||||
@QField(maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.ERROR, dynamicDefaultValueBehavior = DynamicDefaultValueBehavior.USER_ID)
|
||||
private String userId;
|
||||
|
||||
@QField(label = "Query Filter")
|
||||
private String queryFilterJson;
|
||||
|
||||
@QField(label = "Columns")
|
||||
private String columnsJson;
|
||||
|
||||
@QField(label = "Input Fields")
|
||||
private String inputFieldsJson;
|
||||
|
||||
@QField(label = "Pivot Table")
|
||||
private String pivotTableJson;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedReport()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedReport(QRecord qRecord) throws QException
|
||||
{
|
||||
populateFromQRecord(qRecord);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for id
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for id
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setId(Integer id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for createDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Instant getCreateDate()
|
||||
{
|
||||
return createDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for createDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCreateDate(Instant createDate)
|
||||
{
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for modifyDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Instant getModifyDate()
|
||||
{
|
||||
return modifyDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for modifyDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setModifyDate(Instant modifyDate)
|
||||
{
|
||||
this.modifyDate = modifyDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedReport withLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedReport withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for userId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for userId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setUserId(String userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for userId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedReport withUserId(String userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queryFilterJson
|
||||
*******************************************************************************/
|
||||
public String getQueryFilterJson()
|
||||
{
|
||||
return (this.queryFilterJson);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for queryFilterJson
|
||||
*******************************************************************************/
|
||||
public void setQueryFilterJson(String queryFilterJson)
|
||||
{
|
||||
this.queryFilterJson = queryFilterJson;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for queryFilterJson
|
||||
*******************************************************************************/
|
||||
public SavedReport withQueryFilterJson(String queryFilterJson)
|
||||
{
|
||||
this.queryFilterJson = queryFilterJson;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for columnsJson
|
||||
*******************************************************************************/
|
||||
public String getColumnsJson()
|
||||
{
|
||||
return (this.columnsJson);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for columnsJson
|
||||
*******************************************************************************/
|
||||
public void setColumnsJson(String columnsJson)
|
||||
{
|
||||
this.columnsJson = columnsJson;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for columnsJson
|
||||
*******************************************************************************/
|
||||
public SavedReport withColumnsJson(String columnsJson)
|
||||
{
|
||||
this.columnsJson = columnsJson;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for inputFieldsJson
|
||||
*******************************************************************************/
|
||||
public String getInputFieldsJson()
|
||||
{
|
||||
return (this.inputFieldsJson);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for inputFieldsJson
|
||||
*******************************************************************************/
|
||||
public void setInputFieldsJson(String inputFieldsJson)
|
||||
{
|
||||
this.inputFieldsJson = inputFieldsJson;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for inputFieldsJson
|
||||
*******************************************************************************/
|
||||
public SavedReport withInputFieldsJson(String inputFieldsJson)
|
||||
{
|
||||
this.inputFieldsJson = inputFieldsJson;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for pivotTableJson
|
||||
*******************************************************************************/
|
||||
public String getPivotTableJson()
|
||||
{
|
||||
return (this.pivotTableJson);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for pivotTableJson
|
||||
*******************************************************************************/
|
||||
public void setPivotTableJson(String pivotTableJson)
|
||||
{
|
||||
this.pivotTableJson = pivotTableJson;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for pivotTableJson
|
||||
*******************************************************************************/
|
||||
public SavedReport withPivotTableJson(String pivotTableJson)
|
||||
{
|
||||
this.pivotTableJson = pivotTableJson;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.savedreports;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.savedreports.RenderSavedReportMetaDataProducer;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class SavedReportsMetaDataProvider
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
instance.addTable(defineSavedReportTable(backendName, backendDetailEnricher));
|
||||
instance.addPossibleValueSource(defineSavedReportPossibleValueSource());
|
||||
instance.addProcess(new RenderSavedReportMetaDataProducer().produce(instance));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QTableMetaData defineSavedReportTable(String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName(SavedReport.TABLE_NAME)
|
||||
.withLabel("Saved Report")
|
||||
.withIcon(new QIcon().withName("article"))
|
||||
.withRecordLabelFormat("%s")
|
||||
.withRecordLabelFields("label")
|
||||
.withBackendName(backendName)
|
||||
.withPrimaryKeyField("id")
|
||||
.withFieldsFromEntity(SavedReport.class)
|
||||
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "label")))
|
||||
.withSection(new QFieldSection("settings", new QIcon().withName("settings"), Tier.T2, List.of("tableName")))
|
||||
.withSection(new QFieldSection("data", new QIcon().withName("text_snippet"), Tier.T2, List.of("queryFilterJson", "columnsJson", "pivotTableJson")))
|
||||
.withSection(new QFieldSection("hidden", new QIcon().withName("text_snippet"), Tier.T2, List.of("inputFieldsJson", "userId")).withIsHidden(true))
|
||||
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
|
||||
|
||||
for(String jsonFieldName : List.of("queryFilterJson", "columnsJson", "inputFieldsJson", "pivotTableJson"))
|
||||
{
|
||||
table.getField(jsonFieldName).withFieldAdornment(new FieldAdornment(AdornmentType.CODE_EDITOR).withValue(AdornmentType.CodeEditorValues.languageMode("json")));
|
||||
}
|
||||
|
||||
if(backendDetailEnricher != null)
|
||||
{
|
||||
backendDetailEnricher.accept(table);
|
||||
}
|
||||
|
||||
return (table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QPossibleValueSource defineSavedReportPossibleValueSource()
|
||||
{
|
||||
return QPossibleValueSource.newForTable(SavedReport.TABLE_NAME);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportDestination;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RenderSavedReportExecuteStep implements BackendStep
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
SavedReport savedReport = new SavedReport(runBackendStepInput.getRecords().get(0));
|
||||
File tmpFile = File.createTempFile("SavedReport" + savedReport.getId(), ".xlsx", new File("/tmp/"));
|
||||
|
||||
runBackendStepInput.getAsyncJobCallback().updateStatus("Generating Report");
|
||||
|
||||
QReportMetaData reportMetaData = new SavedReportToReportMetaDataAdapter().adapt(savedReport);
|
||||
|
||||
try(FileOutputStream reportOutputStream = new FileOutputStream(tmpFile))
|
||||
{
|
||||
ReportInput reportInput = new ReportInput();
|
||||
reportInput.setReportMetaData(reportMetaData);
|
||||
reportInput.setReportDestination(new ReportDestination()
|
||||
.withReportFormat(ReportFormat.XLSX) // todo - variable
|
||||
.withReportOutputStream(reportOutputStream));
|
||||
|
||||
Map<String, Serializable> values = runBackendStepInput.getValues();
|
||||
reportInput.setInputValues(values);
|
||||
|
||||
new GenerateReportAction().execute(reportInput);
|
||||
}
|
||||
|
||||
String downloadFileBaseName = getDownloadFileBaseName(runBackendStepInput, savedReport);
|
||||
runBackendStepOutput.addValue("downloadFileName", downloadFileBaseName + ".xlsx");
|
||||
runBackendStepOutput.addValue("serverFilePath", tmpFile.getCanonicalPath());
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
// todo - render error screen?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private String getDownloadFileBaseName(RunBackendStepInput runBackendStepInput, SavedReport report)
|
||||
{
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HHmm").withZone(ZoneId.systemDefault());
|
||||
String datePart = formatter.format(Instant.now());
|
||||
|
||||
String downloadFileBaseName = runBackendStepInput.getValueString("downloadFileBaseName");
|
||||
if(!StringUtils.hasContent(downloadFileBaseName))
|
||||
{
|
||||
downloadFileBaseName = report.getLabel();
|
||||
}
|
||||
|
||||
downloadFileBaseName = downloadFileBaseName.replaceAll("/", "-");
|
||||
|
||||
return (downloadFileBaseName + " - " + datePart);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RenderSavedReportMetaDataProducer implements MetaDataProducerInterface<QProcessMetaData>
|
||||
{
|
||||
public static final String NAME = "renderSavedReport";
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public QProcessMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData()
|
||||
.withName(NAME)
|
||||
.withTableName(SavedReport.TABLE_NAME)
|
||||
.withIcon(new QIcon().withName("print"))
|
||||
.addStep(new QBackendStepMetaData()
|
||||
.withName("pre")
|
||||
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData()
|
||||
.withTableName(SavedReport.TABLE_NAME)))
|
||||
.withCode(new QCodeReference(RenderSavedReportPreStep.class)))
|
||||
.addStep(new QFrontendStepMetaData()
|
||||
.withName("input")
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM)))
|
||||
.addStep(new QBackendStepMetaData()
|
||||
.withName("execute")
|
||||
.withInputData(new QFunctionInputMetaData().withRecordListMetaData(new QRecordListMetaData()
|
||||
.withTableName(SavedReport.TABLE_NAME)))
|
||||
.withCode(new QCodeReference(RenderSavedReportExecuteStep.class)))
|
||||
// todo - no no, stream the damn thing... how to do that??
|
||||
.addStep(new QFrontendStepMetaData()
|
||||
.withName("output")
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.DOWNLOAD_FORM)));
|
||||
|
||||
return (process);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RenderSavedReportPreStep implements BackendStep
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
// todo - verify ran on 1
|
||||
// todo - load the SavedReport
|
||||
// todo - check for inputs - set up the input screen...
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.processes.implementations.savedreports;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.reporting.pivottable.PivotTableDefinition;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportField;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportView;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.ReportType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.savedreports.SavedReport;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.ListBuilder;
|
||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class SavedReportToReportMetaDataAdapter
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(SavedReportToReportMetaDataAdapter.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QReportMetaData adapt(SavedReport savedReport) throws QException
|
||||
{
|
||||
try
|
||||
{
|
||||
QReportMetaData reportMetaData = new QReportMetaData();
|
||||
reportMetaData.setLabel(savedReport.getLabel());
|
||||
|
||||
////////////////////////////
|
||||
// set up the data-source //
|
||||
////////////////////////////
|
||||
QReportDataSource dataSource = new QReportDataSource();
|
||||
reportMetaData.setDataSources(List.of(dataSource));
|
||||
dataSource.setName("main");
|
||||
|
||||
QTableMetaData table = QContext.getQInstance().getTable(savedReport.getTableName());
|
||||
dataSource.setSourceTable(savedReport.getTableName());
|
||||
|
||||
dataSource.setQueryFilter(JsonUtils.toObject(savedReport.getQueryFilterJson(), QQueryFilter.class));
|
||||
|
||||
// todo!!! oh my.
|
||||
List<QueryJoin> queryJoins = null;
|
||||
dataSource.setQueryJoins(queryJoins);
|
||||
|
||||
//////////////////////////
|
||||
// set up the main view //
|
||||
//////////////////////////
|
||||
QReportView view = new QReportView();
|
||||
reportMetaData.setViews(ListBuilder.of(view));
|
||||
view.setName("main");
|
||||
view.setType(ReportType.TABLE);
|
||||
view.setDataSourceName(dataSource.getName());
|
||||
view.setLabel(savedReport.getLabel()); // todo eh?
|
||||
view.setIncludeHeaderRow(true);
|
||||
|
||||
// don't need:
|
||||
// view.setOrderByFields(); - only used for summary reports
|
||||
// view.setTitleFormat(); - not using at this time
|
||||
// view.setTitleFields(); - not using at this time
|
||||
// view.setRecordTransformStep();
|
||||
// view.setViewCustomizer();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// columns in the saved-report look like a JSON object, w/ a key "columns", which is an array of objects //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Map<String, Object> columnsObject = JsonUtils.toObject(savedReport.getColumnsJson(), new TypeReference<>() {});
|
||||
List<Map<String, Object>> columns = (List<Map<String, Object>>) columnsObject.get("columns");
|
||||
List<QReportField> reportColumns = new ArrayList<>();
|
||||
|
||||
for(Map<String, Object> column : columns)
|
||||
{
|
||||
if(column.containsKey("isVisible") && !"true".equals(ValueUtils.getValueAsString(column.get("isVisible"))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QFieldMetaData field = null;
|
||||
String fieldName = ValueUtils.getValueAsString(column.get("name"));
|
||||
if(fieldName.contains("."))
|
||||
{
|
||||
// todo - join!
|
||||
}
|
||||
else
|
||||
{
|
||||
field = table.getFields().get(fieldName);
|
||||
if(field == null)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// frontend may often pass __checked__ (or maybe other __ prefixes in the future - so - don't warn that. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(!fieldName.startsWith("__"))
|
||||
{
|
||||
LOG.warn("Saved Report has an unexpected unrecognized field name", logPair("savedReportId", savedReport.getId()), logPair("table", table.getName()), logPair("fieldName", fieldName));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
QReportField reportField = new QReportField();
|
||||
reportColumns.add(reportField);
|
||||
|
||||
reportField.setName(fieldName);
|
||||
reportField.setLabel(field.getLabel());
|
||||
|
||||
if(StringUtils.hasContent(field.getPossibleValueSourceName()))
|
||||
{
|
||||
reportField.setShowPossibleValueLabel(true);
|
||||
}
|
||||
}
|
||||
|
||||
view.setColumns(reportColumns);
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// if it's a pivot report, add that view too //
|
||||
///////////////////////////////////////////////
|
||||
if(StringUtils.hasContent(savedReport.getPivotTableJson()))
|
||||
{
|
||||
QReportView pivotView = new QReportView();
|
||||
reportMetaData.getViews().add(pivotView);
|
||||
pivotView.setName("pivot"); // does this appear?
|
||||
pivotView.setType(ReportType.PIVOT);
|
||||
pivotView.setPivotTableSourceViewName(view.getName());
|
||||
pivotView.setPivotTableDefinition(JsonUtils.toObject(savedReport.getPivotTableJson(), PivotTableDefinition.class));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// add input fields, if they're in the savedReport //
|
||||
/////////////////////////////////////////////////////
|
||||
if(StringUtils.hasContent(savedReport.getInputFieldsJson()))
|
||||
{
|
||||
reportMetaData.setInputFields(JsonUtils.toObject(savedReport.getInputFieldsJson(), new TypeReference<>() {}));
|
||||
}
|
||||
|
||||
return (reportMetaData);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error adapting savedReport to reportMetaData", e, logPair("savedReportId", savedReport.getId()));
|
||||
throw (new QException("Error adapting savedReport to reportMetaData", e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user