import { CloseFormInstructionType, } from './WindowManager'; import { ComponentModel, objectParameter } from './cykLang' import { computed, Ref, ref, SetupContext } from 'vue'; import loglevel from 'loglevel'; import { data2boolean, Expression, FunctionData, ObjectData, PrimitiveData, Variable, variable2json, Variables, XmlError, } from '@cyklang/core'; const logger = loglevel.getLogger('cykQTable.ts'); logger.setLevel('debug'); // import { structure } from 'src/services/cyklang'; import { useCykLang } from './cykLang'; import { AlertException } from './cykRun'; import { buildQColumns, calComputedCols, Command, loadRecords } from './cykTableView'; import { parseOptions } from './cykTableOptions'; import { RowObject } from './cykTableEdit'; const { structure } = useCykLang() //------------------------------------------------------------------ // useCykQTable // main function //------------------------------------------------------------------ interface ResultUseCykQTable { isLoading: Ref, rowObjects: Ref, row_key_fn: (row: RowObject) => string, qColumns: any[], filter: Ref, selection: Ref>, pagination: any, tableCmds: ObjectData[], optCmds: Variable | undefined, clickCmdButton: (row: ObjectData | undefined, cmdObject: ObjectData) => Promise, setOptSelected: (row: ObjectData | undefined, cmdName: string) => void, optionsObject: ObjectData, optSelected: Ref, onload: () => Promise } export function useCykQTable(props: { componentArg: ComponentModel | undefined }, context: SetupContext<'reload'[]>): ResultUseCykQTable { // logger.debug('useCykQTable begins') const selection: Ref> = ref([]) if ( props.componentArg === undefined || props.componentArg.model === undefined || props.componentArg.objectData === undefined ) { throw Error('QTable componentArg undefined'); } if ( props.componentArg.model.data === null || props.componentArg.model.data === undefined ) throw ' model.data undefined'; if (props.componentArg.model.data.type.isPrimitive()) throw ' model must be an object'; const isLoading = ref(true); const filter = ref(''); const rowKeyName = ref(''); const optSelected: Ref = ref(); const qColumns: any[] = [] const rowObjects: Ref = ref([]); const commands: Command[] = []; const tableCommands: Command[] = []; const tableCmds: ObjectData[] = []; const queryFunct: Ref = ref(); //------------------------------------------------------------------- // function row_key_fn // returns row key const row_key_fn = (row: RowObject) => { let result = ''; try { const keyElts = rowKeyName.value.split(';') for (let ind = 0; ind < keyElts.length; ind++) { if (ind > 0) result += '\t' result += row.objectData.variables.getString(keyElts[ind]) } } catch (err) { logger.error(err) } return result; }; const setOptSelected = (row: ObjectData | undefined, cmdName: string) => { if (!optSelected || optSelected.value === undefined) return; let varSelectedRow = optSelected.value?.variables.getVariable('row'); if (varSelectedRow === undefined) { varSelectedRow = optSelected.value?.variables.addVariable( 'row', optSelected.value?.scope.structure.objectDataType ); } if (row) { varSelectedRow.data = row; } let varSelectedCommand = optSelected.value?.variables.getVariable('command'); if (varSelectedCommand === undefined) { varSelectedCommand = optSelected.value?.variables.addVariable( 'command', optSelected.value.scope.structure.stringDataType ); } varSelectedCommand.data = new PrimitiveData( varSelectedCommand.dataType, cmdName ); }; /** * * @param row * @param cmdObject */ async function clickCmdButton( row: ObjectData | undefined, cmdObject: ObjectData ) { try { // const scope = (props.componentArg?.model?.data as ObjectData)?.scope || optSelected.value?.scope const scope = cmdObject.scope const cmdName = objectParameter(cmdObject, "name", "") setOptSelected(row, cmdName) const cmdAction = objectParameter(cmdObject, "action", "") let cmdOnClick = cmdObject.variables.getFunction("onclick") if (cmdAction && cmdAction !== '__reload__' && !cmdOnClick) { const express = new Expression(scope) const dataAction = await express.evaluate(cmdAction) if (!(dataAction instanceof FunctionData)) { throw 'action function not found: ' + cmdAction } cmdOnClick = dataAction } if (cmdOnClick) { const params = new Variables() if (row) { const parametersDefinition = cmdOnClick.parametersDefinition if (!parametersDefinition) throw 'function onclick() or action should have the selected row as argument' const parameterDefinition = parametersDefinition.array[0]; if (!parameterDefinition.dataType.isObject()) throw 'function onclick() or action first argument should be an object' const varParam = params.addVariable(parameterDefinition.name, parameterDefinition.dataType) varParam.data = row } const dataReturned = await cmdOnClick.callFunction(params, scope) const reload = data2boolean(dataReturned) if (reload) { context.emit('reload') } } else if (cmdAction === '__reload__') { context.emit('reload') } else { // close this form and return row and command selected const closeformInstType = await optSelected.value?.scope.lookupInstructionType( 'closeform' ) as CloseFormInstructionType; if (closeformInstType === undefined) throw 'closeform instruction type not found'; await closeformInstType.windowManager.closeForm(); } } catch (err) { AlertException(err) } } const pagine = ref({ descending: false, page: 1, rowsPerPage: 15, }) if (props.componentArg.objectData.tag.attributes.ROWS_PER_PAGE) { pagine.value.rowsPerPage = Number(props.componentArg.objectData.tag.attributes.ROWS_PER_PAGE) logger.debug('attribute ROWS_PER_PAGE : ' + pagine.value.rowsPerPage) } const LS_ROWS_PER_PAGE = 'cyk:ROWS-PER-PAGE' const item = localStorage.getItem(LS_ROWS_PER_PAGE) if (item) { pagine.value.rowsPerPage = Number(item) } const pagination = computed({ get() { // logger.debug('pagination.get: ', pagine.value) return pagine.value }, set(nval: any) { // logger.debug('pagination.set: ', nval ) pagine.value.page = nval.page pagine.value.rowsPerPage = nval.rowsPerPage localStorage.setItem(LS_ROWS_PER_PAGE, String(pagine.value.rowsPerPage)) } }); //------------------------------------------------------------------- // options validation const optionsObject = (props.componentArg?.model?.data as ObjectData); const { // eslint-disable-next-line @typescript-eslint/no-unused-vars dbResult, optEntity, optCommands, optColumns, optTableCommands, optCmds, onloadFunct } = parseOptions(optionsObject, optSelected, queryFunct); //------------------------------------------------------------------- // calculate Computed Columns //------------------------------------------------------------------- (async () => { // logger.debug('loading...'); try { //------------------------------------------------------------------- // buildQColumns const { dbColumns, columns } = await buildQColumns( 'dialog', dbResult, optEntity, optColumns, optionsObject, optCommands, rowKeyName, qColumns, ); //------------------------------------------------------------------- // q-table rows building loadRecords(rowObjects, dbResult, optEntity, optionsObject); // logger.debug('loadRecords records:', records) //------------------------------------------------------------------- // buildCommands // buildCommands(optCommands, optionsObject, commands); // tableCommands building // buildTableCommands(optTableCommands, optionsObject, tableCommands); if (optTableCommands) { optTableCommands.variables.forEach(({ variable }) => { const data = variable.data if (data && data !== null && data instanceof ObjectData) { const visible = objectParameter(data, "visible", true) if (visible) { tableCmds.push(data) } } }) } await calComputedCols(columns, rowObjects); /** * */ const varRow = optSelected.value?.variables.getVariable('row'); selection.value.length = 0; if (varRow !== undefined && varRow.data !== undefined && varRow.data !== null) { if (!varRow.data.type.isObject()) throw 'selected.row should be object but is ' + varRow.data.type.name const objRow = varRow.data as ObjectData const jsonRow = variable2json(varRow) const keyToSelect = dbColumns.keyPack(jsonRow) for (let ind = 0; ind < rowObjects.value.length; ind++) { const record = rowObjects.value[ind].objectData // const varRecord = new Variable(record.type, record) const key = dbColumns.keyPack(record.variables.json()) if (key === keyToSelect) { selection.value.push(new RowObject(record)) varRow.data = record const rowsPerPage = pagine.value.rowsPerPage as number; // logger.debug('pagine.rowsPerPage : ' + rowsPerPage) pagine.value.page = Math.floor(ind / rowsPerPage) + 1 break; } } } // logger.debug('QTable.setup selection:', selection.value) } catch (err) { logger.error(err); } })().finally(() => { isLoading.value = false; }); const onload = async () => { if (props.componentArg?.objectData) try { if (onloadFunct) { await onloadFunct.callFunction(new Variables(), props.componentArg.objectData.scope) } } catch (err) { AlertException(new XmlError(String(err), props.componentArg.objectData.tag)) } } return { isLoading, rowObjects, // rowKeyName, row_key_fn, qColumns, // clickCommandButton, // commands, // tableCommands, filter, // row_click, selection, pagination, // optTableCommands, tableCmds, optCmds, clickCmdButton, setOptSelected, optionsObject, optSelected, onload }; }