Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Templates for dataGrid columns #153

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
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
21,050 changes: 20,976 additions & 74 deletions packages/react-lowcode/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/react-lowcode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Automate React Apps.",
"scripts": {
"build": "npx tsc",
"watch": "npx tsc --watch",
"tscd": "npx tsc --emitDeclarationOnly",
"tsc": "npx tsc",
"etsc": "etsc",
Expand Down
4 changes: 2 additions & 2 deletions packages/react-lowcode/src/codegen/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ts, { factory } from "typescript"
import { Property } from './generation/entity/index'
import { CodegenOptions } from './interfaces'
import TemplateResolver from './generation/generators/template/template-resolver'
import { IntrospectionQuery, getNestedOfType, generateGraphqlFile, getEntity, getQueryNames } from '@iteria-app/graphql-lowcode/src/generate'
import { IntrospectionQuery, getNestedOfType, generateGraphqlFile, getEntity } from "@iteria-app/graphql-lowcode/esm/generate"

// generates CRUD React pages (master-detail, eg. orders list, order detail form) from typescript
export function generatePages(introspection: IntrospectionQuery, io: CodeRW & CodeDir, options?: CodegenOptions) {
Expand Down Expand Up @@ -34,7 +34,7 @@ export function generatePages(introspection: IntrospectionQuery, io: CodeRW & Co
properties: props
}

let context = { uiFramework: UiFramework.MaterialUI, formatter: Formatter.None, index: { tableType: TableType.BasicTable, height: "400px" } };
let context = { uiFramework: UiFramework.MaterialUI, formatter: Formatter.ReactIntl, index: { tableType: TableType.DataTable, height: "400px" } };

const generator = new AppGenerator(context, entity)
const page = generator.generateListComponent(/* TODO entity / type name should be input - not in context */)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { defineComponent } from '../../generation/react-components/react-compone

export const muiCore = '@material-ui/core'
export const muiDataGrid = '@material-ui/data-grid'
export const intl = 'react-intl'

export const MuiTableComponents = {
table: defineComponent('Table', muiCore),
Expand All @@ -16,3 +17,7 @@ export const MuiDtTableComponents = {
table: defineComponent('DataGrid', muiDataGrid),
gridColParams: defineComponent('GridColParams', muiDataGrid)
}

export const FormattedComponents = {
message: defineComponent('FormattedMessage', intl)
}
2 changes: 1 addition & 1 deletion packages/react-lowcode/src/codegen/facade/facadeApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export async function insertColumn(

let generator = new MuiDataTableGenerator(
generationContext,
undefined,
options.entity,
widgetContext
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import ts, { factory, SourceFile, PropertyAssignment, Node, ImportDeclaration, Identifier, NodeArray, Statement } from "typescript"
import { getPropertyType, PropertyType } from '../../graphql/typeAlias'
import { createFunctionalComponent, PageComponent, createJsxSelfClosingElement, createJsxAttribute } from '../../react-components/react-component-helper'
import { createFunctionalComponent, PageComponent } from '../../react-components/react-component-helper'
import { Entity, getProperties, Property } from '../../entity/index'
import { TableGenerator } from './table-generator-factory'
import GenerationContext from "../../context/context"
import { MuiDtTableComponents, muiDataGrid } from '../../../definition/material-ui/table'
import { MuiDtTableComponents, muiDataGrid, intl } from '../../../definition/material-ui/table'
import { TableComponentDefinitionBase } from '../../../definition/table-definition-core'
import { Formatter } from "../../../definition/context-types"
import { createNameSpaceImport, uniqueImports } from "../../../ast/imports"
Expand Down Expand Up @@ -172,14 +171,14 @@ export default class MuiDataTableGenerator implements TableGenerator
property: Property,
ast:SourceFile,
columnIndex?: number): ts.SourceFile{
let newColumnsDefinition = this.getNewColumnsDeclaration(columnDeclarationParent,
property,
columnIndex)
return replaceElementsToAST(ast,
columnDeclarationParent.pos,
factory.createArrayLiteralExpression(newColumnsDefinition))

const newColumnsDefinition = this.getNewColumnsDeclaration(columnDeclarationParent,
property,
columnIndex)

return replaceElementsToAST(ast,
columnDeclarationParent.pos,
factory.createArrayLiteralExpression(newColumnsDefinition))
}

private getNewColumnsDeclaration(columnDeclarationParent: ts.ArrayLiteralExpression,
Expand All @@ -188,8 +187,8 @@ export default class MuiDataTableGenerator implements TableGenerator
let newElements: ts.Expression[] = []
let oldElements = columnDeclarationParent.elements

let newColumnDefinition = this.createColumnDefinition(property, this.getUsedFormatter(columnDeclarationParent))
let newColumnDefinition = this.createNewDataGridColumn(property) as ts.ObjectLiteralExpression // this.createColumnDefinition(property, this.getUsedFormatter(columnDeclarationParent))

if(columnIndex && columnIndex > 0 && columnIndex < oldElements.length + 1){
newElements = [...oldElements.slice(0, columnIndex-1),
newColumnDefinition,
Expand Down Expand Up @@ -250,80 +249,44 @@ export default class MuiDataTableGenerator implements TableGenerator

if(this._context.formatter === Formatter.ReactIntl){
statements.push(this._intlFormatter.getImperativeHook())
statements.push(this._intlFormatter.getNavigateHook())
}

let columnsIdentifier = factory.createIdentifier("columns")
let columnsDeclaration = this.createColumns(columnsIdentifier)

var columnsAttribute = createJsxAttribute("columns", "columns")
statements.push(factory.createVariableStatement(undefined, columnsDeclaration))

var rowsAttribute = createJsxAttribute("rows", this._helper.getInputParameterIdentifier(this._entity!))
const value = this._helper.getInputParameterIdentifier(this._entity!)

let returnStatement = this.createReturnStatement([columnsAttribute, rowsAttribute])
let returnStatement = this.createReturnStatement((columnsDeclaration.declarations[0].name as any).escapedText, value.escapedText)

statements.push(returnStatement)

return statements;
}

private createReturnStatement(parameters: ts.JsxAttributeLike[]):ts.ReturnStatement {
var dataGridComponent = this._helper.prepareComponent(this.getTableDefinition().table, this._imports);

let wrappedTable = this.createTableWrapper(createJsxSelfClosingElement(dataGridComponent.tagName, parameters))

return factory.createReturnStatement(factory.createParenthesizedExpression(wrappedTable))
}

private createTableWrapper(datagrid:ts.JsxSelfClosingElement) {
return factory.createJsxElement(
factory.createJsxOpeningElement(
factory.createIdentifier("div"),
undefined,
factory.createJsxAttributes([factory.createJsxAttribute(
factory.createIdentifier("style"),
factory.createJsxExpression(
undefined,
factory.createObjectLiteralExpression(
[
factory.createPropertyAssignment(
factory.createIdentifier("height"),
factory.createStringLiteral(this._context?.index?.height ?? "400px")
),
factory.createPropertyAssignment(
factory.createIdentifier("width"),
factory.createStringLiteral("100%")
)
],
false
)
)
)])
),
[
factory.createJsxText(
"\
",
true
),
datagrid,
factory.createJsxText(
"\
",
true
)
],
factory.createJsxClosingElement(factory.createIdentifier("div"))
private createReturnStatement(columns: string, rows: any):ts.ReturnStatement {
const table = this.createTemplateForDataGrid(columns, rows)

const test = factory.createJsxElement(
this.createTable(table) as any,
[],
undefined as any
)

return factory.createReturnStatement(factory.createParenthesizedExpression(test))
}

private createColumns(columnsIdentifier: ts.Identifier):ts.VariableDeclarationList {
let propertiesColumnDefinitions = Array<ts.ObjectLiteralExpression>()

getProperties(this._entity!).forEach(property => {
propertiesColumnDefinitions.push(this.createColumnDefinition(property, this._context.formatter??Formatter.None))
const column = this.createNewDataGridColumn(property)
if (column)
propertiesColumnDefinitions.push(column) // this.createColumnDefinition(property, this._context.formatter??Formatter.None)
});

return factory.createVariableDeclarationList(
[factory.createVariableDeclaration(
columnsIdentifier,
Expand All @@ -338,113 +301,106 @@ export default class MuiDataTableGenerator implements TableGenerator
)
}

private createColumnDefinition(property: Property, formatter: Formatter): ts.ObjectLiteralExpression {
let propertyName = property.getName()
let propType: PropertyType = getPropertyType(property)
let muiColumnType = 'string'
private createNewDataGridColumn(
property: Property
): ts.ObjectLiteralExpression | undefined {

const template = this.createTemplateForColumn(property)
if (template) {
const tree = createAst(template)
if (tree) {
const columnElement = findByCondition<ts.JsxChild>(tree, (node: ts.Node) => {
return ts.isJsxText(node) || ts.isJsxExpression(node) || ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node) || ts.isJsxFragment(node) || ts.isBlock(node);
})
if (columnElement) {
this.clearNodePosition(columnElement)
return this.createLiteralGridColumn(columnElement)
}
}
}
return undefined
}


private createTemplateForColumn(property: Property) {
const name = property.getName()
const type = property.getType().toLowerCase()

//TODO: datetime is not working for numbers, find out why
switch(propType) {
case PropertyType.currency:
case PropertyType.numeric:
muiColumnType = 'number'
let template = ``
switch(type) {
case("string"):
case("number"):
case("boolean"):
case("int"):
case("jsonb"):
case("uuid"):
template = `{ field: "${name}" flex: ${1} type: "${type}" valueFormatter: ({ value }) => value renderHeader: ${this.renderHeaderTemplate(property)}}`
break
case("date"):
template = `{ field: "${name}" flex: ${1} type: "${type}" valueFormatter: ({ value }) => intl.formatDate(value) renderHeader: ${this.renderHeaderTemplate(property)}}`
break
case("dateTime"):
case("timestamptz"):
template = `{ field: "${name}" flex: ${1} type: "${type}" valueFormatter: ({ value }) => intl.formatDate(value) + ", " + intl.formatTime(value) renderHeader: ${this.renderHeaderTemplate(property)}}`
break
case PropertyType.date:
case PropertyType.datetime:
muiColumnType = 'date'
default:
template = ''
break
}

return template
}

let properties : ts.ObjectLiteralElementLike[] =
[
factory.createPropertyAssignment(
factory.createIdentifier("field"),
factory.createStringLiteral(propertyName)
),
factory.createPropertyAssignment(
factory.createIdentifier("flex"),
factory.createNumericLiteral(1)
),
factory.createPropertyAssignment(
factory.createIdentifier("type"),
factory.createStringLiteral(muiColumnType)
)
];

if(formatter === Formatter.ReactIntl){
properties.push(factory.createPropertyAssignment(
factory.createIdentifier("valueFormatter"),
this.getValueFormatter(property)
))

properties.push(factory.createPropertyAssignment(
factory.createIdentifier("renderHeader"),
this.getHeaderRender(property)
))
}else{
properties.push(factory.createPropertyAssignment(
factory.createIdentifier("headerName"),
factory.createStringLiteral(property.getName())
))
private clearNodePosition = (node: ts.Node): void => {
ts.setTextRange(node, { pos: -1, end: -1 });

node.forEachChild((child: ts.Node) => {
this.clearNodePosition(child);
});
}


private createLiteralGridColumn(element: any) {
let el : any = []
for (let i in element.statements) {
if (element.statements[i].kind !== undefined) {
el.push(
factory.createPropertyAssignment(
element.statements[i].label.escapedText,
element.statements[i].statement.expression
)
)
}
}

let expression = factory.createObjectLiteralExpression(
properties,
return factory.createObjectLiteralExpression(
el,
false
)

return expression;
}

private getHeaderRender(property: Property): ts.ArrowFunction {
private renderHeaderTemplate(property: Property) {
let declaration = this._helper.addImportDeclaration('GridColParams', muiDataGrid)
this._imports.push(declaration)
declaration = this._helper.addImportDeclaration('FormattedMessage', intl)
this._imports.push(declaration)
return `(params : GridColsParams) => (<FormattedMessage id="${this._entity?.getName()}" defaultMessage="${property.getName()}"/>)`
}

public createTemplateForDataGrid(columns: string, rows: string) {
let declaration = this._helper.addImportDeclaration('DataGrid', muiDataGrid)
this._imports.push(declaration)

let localizedProperty = this._intlFormatter.localizePropertyNameUsingTag(property, this._entity)

return factory.createArrowFunction(
undefined,
undefined,
[factory.createParameterDeclaration(
undefined,
undefined,
undefined,
factory.createIdentifier("params"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("GridColParams"),
undefined
),
undefined
)],
undefined,
factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
factory.createParenthesizedExpression(localizedProperty)
)
let template = `<DataGrid onRowClick={() => navigate('/app/generated-customer-detail', { replace: true })} columns={${columns}} rows={${rows}} pageSize={5} rowsPerPageOptions={[2, 3, 4, 5, 6, 20]} />`

return template
}

private getValueFormatter(prop: Property): ts.ArrowFunction {
return factory.createArrowFunction(
undefined,
undefined,
[factory.createParameterDeclaration(
undefined,
undefined,
undefined,
factory.createObjectBindingPattern([factory.createBindingElement(
undefined,
undefined,
factory.createIdentifier("value"),
undefined
)]),
undefined,
undefined,
undefined
)],
undefined,
factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
this._intlFormatter.formatPropertyUsingImperative(prop, factory.createIdentifier("value"), factory.createIdentifier("value"))
)
public createTable(dataGrid: string) {
return this.createTemplateForWrapper(dataGrid)
}

private createTemplateForWrapper(dataGrid: string) {
return factory.createIdentifier(`<div style={{ height: "400px", width: "100%" }}>${dataGrid}</div>`)
}
}
Loading