Checkpoint to get cypress working - auth-type from backend, less hard-coded auth0, improvements on query screen (less redundant fetches)

This commit is contained in:
2022-11-15 16:42:54 -06:00
parent c5780df58e
commit 94002f0d16
21 changed files with 2236939 additions and 344 deletions

1
cypress/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
videos

View File

@ -0,0 +1,105 @@
/// <reference types="cypress-wait-for-stable-dom" />
describe("table query screen", () =>
{
before(() =>
{
cy.intercept("GET", "/metaData/authentication", {fixture: "metaData/authentication.json"}).as("authenticationMetaData");
cy.intercept("GET", "/metaData", {fixture: "metaData/index.json"}).as("metaData");
cy.intercept("GET", "/metaData/table/person", {fixture: "metaData/table/person.json"}).as("personMetaData");
cy.intercept("POST", "/data/person/query?*", {fixture: "data/person/index.json"}).as("personQuery");
cy.intercept("POST", "/data/person/count", {fixture: "data/person/count.json"}).as("personCount");
cy.intercept("POST", "/data/city/count", {fixture: "data/city/count.json"}).as("cityCount");
cy.intercept("GET", "/metaData/process/person.bulkEdit", {fixture: "metaData/process/person.bulkEdit.json"}).as("personBulkEditMetaData");
cy.intercept("POST", "/processes/person.bulkEdit/init?recordsParam=recordIds&recordIds=1,2,3,4,5", {fixture: "processes/person.bulkEdit/init.json"}).as("personBulkEditInit");
cy.intercept("POST", "/processes/person.bulkEdit/74a03a7d-2f53-4784-9911-3a21f7646c43/step/edit", {fixture: "processes/person.bulkEdit/step/edit.json"}).as("personBulkEditStepEdit");
cy.intercept("GET", "/processes/person.bulkEdit/74a03a7d-2f53-4784-9911-3a21f7646c43/records?skip=0&limit=10", {fixture: "processes/person.bulkEdit/records.json"}).as("personBulkEditRecords");
cy.intercept("GET", "/widget/* ", {fixture: "widget/empty.json"}).as("emptyWidget");
});
it("can be loaded from app screen", () =>
{
cy.visit("https://localhost:3000/peopleApp/greetingsApp/");
cy.contains("Person").click();
cy.location().should((loc) =>
{
expect(loc.pathname).to.eq("/peopleApp/greetingsApp/person");
});
});
it.only("can add query filters", () =>
{
/////////////////////////////////////////////////////////////
// go to table, wait for filter to run, and rows to appear //
/////////////////////////////////////////////////////////////
cy.visit("https://localhost:3000/peopleApp/greetingsApp/person");
cy.wait(["@personQuery", "@personCount"]);
cy.get(".MuiDataGrid-virtualScrollerRenderZone").children().should("have.length.greaterThan", 3);
/////////////////////////////////////////////////////////////////////
// open the filter window, enter a value, wait for query to re-run //
/////////////////////////////////////////////////////////////////////
cy.contains("Filters").click();
cy.get(".MuiDataGrid-filterForm input.MuiInput-input").should("be.focused").type("1");
cy.wait(["@personQuery", "@personCount"]);
///////////////////////////////////////
// click away from the filter window //
///////////////////////////////////////
cy.get("#root").click("topLeft", {force: true});
cy.contains(".MuiBadge-root", "1").should("be.visible");
///////////////////////////////////////////////////////////////////
// click the 'x' clear icon, then yes, then expect another query //
///////////////////////////////////////////////////////////////////
cy.waitForStableDOM();
cy.get("#clearFiltersButton").should("be.visible").click();
cy.contains("button", "Yes").click();
cy.wait(["@personQuery", "@personCount"]);
cy.contains(".MuiDataGrid-toolbarContainer .MuiBadge-root", "1").should("not.exist");
});
xit("todo delete", () =>
{
// cy.get(".MuiDataGrid-columnHeaders input[type='checkbox']").click();
// cy.contains("button", "Bulk Actions").click();
// cy.contains("li", "Bulk Edit").click();
// ////////////////////////////
// // bulk edit process init //
// ////////////////////////////
// cy.location().should((loc) =>
// {
// expect(loc.pathname).to.eq("/processes/person.bulkEdit");
// expect(loc.search).to.eq("?recordsParam=recordIds&recordIds=1,2,3,4,5");
// });
// cy.wait(["@personBulkEditMetaData"]);
// cy.wait(["@personBulkEditInit"]);
// cy.contains("p[variation='h5']", "Edit Values");
// cy.get("#bulkEditSwitch-firstName").click();
// cy.get("input[name='firstName']").click()
// .type("Kahhhhn");
// cy.contains("button", "next").click();
// ///////////////////////////
// // bulk edit review step //
// ///////////////////////////
// cy.contains("p[variation='h5']", "Review");
// cy.contains(".MuiDataGrid-cellContent", "Kahhhhn");
// cy.contains("button", "submit").click();
// cy.wait(["@personBulkEditStepEdit"]);
// cy.wait(["@personBulkEditRecords"]);
// ////////////////////////////
// // bulk edit result step //
// ////////////////////////////
// cy.contains("p[variation='h5']", "Results");
// cy.wait(["@personBulkEditRecords"]);
});
});

View File

@ -1,72 +0,0 @@
// noinspection ES6UnusedImports
import * as cypress from "cypress";
describe("empty spec", () =>
{
it("passes", () =>
{
cy.intercept("GET", "/metaData", {fixture: "metaData/index.json"}).as("metaData");
cy.intercept("GET", "/data/person?*", {fixture: "data/person/index.json"}).as("personQuery");
cy.intercept("GET", "/data/person/count?*", {fixture: "data/person/count.json"}).as("personCount")
cy.intercept("GET", "/metaData/process/person.bulkEdit", {fixture: "metaData/process/person.bulkEdit.json"}).as("personBulkEditMetaData")
cy.intercept("POST", "/processes/person.bulkEdit/init?recordsParam=recordIds&recordIds=1,2,3,4,5", {fixture: "processes/person.bulkEdit/init.json"}).as("personBulkEditInit")
cy.intercept("POST", "/processes/person.bulkEdit/74a03a7d-2f53-4784-9911-3a21f7646c43/step/edit", {fixture: "processes/person.bulkEdit/step/edit.json"}).as("personBulkEditStepEdit")
cy.intercept("GET", "/processes/person.bulkEdit/74a03a7d-2f53-4784-9911-3a21f7646c43/records?skip=0&limit=10", {fixture: "processes/person.bulkEdit/records.json"}).as("personBulkEditRecords")
/////////////////
// home screen //
/////////////////
cy.visit("http://localhost:3000/");
cy.wait(["@metaData"])
cy.contains(".MuiListItem-root", "Tables").click();
cy.contains(".MuiListItem-root", "Person").click();
/////////////////////////
// person query screen //
/////////////////////////
cy.location().should((loc) =>
{
expect(loc.pathname).to.eq("/person")
});
cy.wait(["@personQuery", "@personCount"])
cy.get(".MuiDataGrid-columnHeaders input[type='checkbox']").click();
cy.contains("button", "Bulk Actions").click();
cy.contains("li", "Bulk Edit").click();
////////////////////////////
// bulk edit process init //
////////////////////////////
cy.location().should((loc) =>
{
expect(loc.pathname).to.eq("/processes/person.bulkEdit");
expect(loc.search).to.eq("?recordsParam=recordIds&recordIds=1,2,3,4,5");
});
cy.wait(["@personBulkEditMetaData"])
cy.wait(["@personBulkEditInit"])
cy.contains("p[variation='h5']", "Edit Values");
cy.get("#bulkEditSwitch-firstName").click();
cy.get("input[name='firstName']").click()
.type("Kahhhhn");
cy.contains("button", "next").click();
///////////////////////////
// bulk edit review step //
///////////////////////////
cy.contains("p[variation='h5']", "Review");
cy.contains(".MuiDataGrid-cellContent", "Kahhhhn");
cy.contains("button", "submit").click();
cy.wait(["@personBulkEditStepEdit"])
cy.wait(["@personBulkEditRecords"])
////////////////////////////
// bulk edit result step //
////////////////////////////
cy.contains("p[variation='h5']", "Results");
cy.wait(["@personBulkEditRecords"])
});
});

View File

@ -0,0 +1,3 @@
{
"count": 101406
}

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,3 @@
{ {
"count": 5 "count": 101406
} }

View File

@ -0,0 +1,4 @@
{
"name": "mock",
"type": "MOCK"
}

View File

@ -1,102 +1,550 @@
{ {
"tables": { "tables": {
"carrier": { "carrier": {
"name": "carrier", "name": "carrier",
"label": "Carrier", "label": "Carrier",
"isHidden": false "isHidden": false,
}, "iconName": "local_shipping",
"city": { "capabilities": [
"name": "city", "TABLE_COUNT",
"label": "Cities", "TABLE_GET",
"isHidden": true "TABLE_QUERY",
}, "TABLE_UPDATE",
"person": { "TABLE_INSERT",
"name": "person", "TABLE_DELETE"
"label": "Person", ]
"isHidden": false },
} "person": {
}, "name": "person",
"processes": { "label": "Person",
"person.bulkInsert": { "isHidden": false,
"name": "person.bulkInsert", "iconName": "person",
"label": "Person Bulk Insert", "capabilities": [
"tableName": "person", "TABLE_COUNT",
"isHidden": true "TABLE_GET",
}, "TABLE_QUERY",
"carrier.bulkInsert": { "TABLE_UPDATE",
"name": "carrier.bulkInsert", "TABLE_INSERT",
"label": "Carrier Bulk Insert", "TABLE_DELETE"
"tableName": "carrier", ]
"isHidden": true },
}, "city": {
"simpleSleep": { "name": "city",
"name": "simpleSleep", "label": "Cities",
"label": "Simple Sleep", "isHidden": true,
"isHidden": true "iconName": "location_city",
}, "capabilities": [
"carrier.bulkDelete": { "TABLE_COUNT",
"name": "carrier.bulkDelete", "TABLE_GET",
"label": "Carrier Bulk Delete", "TABLE_QUERY",
"tableName": "carrier", "TABLE_UPDATE",
"isHidden": true "TABLE_INSERT",
}, "TABLE_DELETE"
"greet": { ]
"name": "greet", }
"label": "Greet People", },
"tableName": "person", "processes": {
"isHidden": true "greet": {
}, "name": "greet",
"city.bulkDelete": { "label": "Greet People",
"name": "city.bulkDelete", "tableName": "person",
"label": "Cities Bulk Delete", "isHidden": true,
"tableName": "city", "iconName": "emoji_people"
"isHidden": true },
}, "greetInteractive": {
"person.bulkDelete": { "name": "greetInteractive",
"name": "person.bulkDelete", "label": "Greet Interactive",
"label": "Person Bulk Delete", "tableName": "person",
"tableName": "person", "isHidden": false,
"isHidden": true "iconName": "waving_hand"
}, },
"carrier.bulkEdit": { "clonePeople": {
"name": "carrier.bulkEdit", "name": "clonePeople",
"label": "Carrier Bulk Edit", "label": "Clone People",
"tableName": "carrier", "tableName": "person",
"isHidden": true "isHidden": false,
}, "iconName": "content_copy"
"person.bulkEdit": { },
"name": "person.bulkEdit", "simpleSleep": {
"label": "Person Bulk Edit", "name": "simpleSleep",
"tableName": "person", "label": "Simple Sleep",
"isHidden": true "isHidden": true
}, },
"greetInteractive": { "sleepInteractive": {
"name": "greetInteractive", "name": "sleepInteractive",
"label": "Greet Interactive", "label": "Sleep Interactive",
"tableName": "person", "isHidden": false
"isHidden": false },
}, "simpleThrow": {
"city.bulkEdit": { "name": "simpleThrow",
"name": "city.bulkEdit", "label": "Simple Throw",
"label": "Cities Bulk Edit", "isHidden": false
"tableName": "city", },
"isHidden": true "carrier.bulkInsert": {
}, "name": "carrier.bulkInsert",
"simpleThrow": { "label": "Carrier Bulk Insert",
"name": "simpleThrow", "tableName": "carrier",
"label": "Simple Throw", "isHidden": true
"isHidden": false },
}, "carrier.bulkEdit": {
"sleepInteractive": { "name": "carrier.bulkEdit",
"name": "sleepInteractive", "label": "Carrier Bulk Edit",
"label": "Sleep Interactive", "tableName": "carrier",
"isHidden": false "isHidden": true
}, },
"city.bulkInsert": { "carrier.bulkDelete": {
"name": "city.bulkInsert", "name": "carrier.bulkDelete",
"label": "Cities Bulk Insert", "label": "Carrier Bulk Delete",
"tableName": "city", "tableName": "carrier",
"isHidden": true "isHidden": true
} },
} "person.bulkInsert": {
"name": "person.bulkInsert",
"label": "Person Bulk Insert",
"tableName": "person",
"isHidden": true
},
"person.bulkEdit": {
"name": "person.bulkEdit",
"label": "Person Bulk Edit",
"tableName": "person",
"isHidden": true
},
"person.bulkDelete": {
"name": "person.bulkDelete",
"label": "Person Bulk Delete",
"tableName": "person",
"isHidden": true
},
"city.bulkInsert": {
"name": "city.bulkInsert",
"label": "Cities Bulk Insert",
"tableName": "city",
"isHidden": true
},
"city.bulkEdit": {
"name": "city.bulkEdit",
"label": "Cities Bulk Edit",
"tableName": "city",
"isHidden": true
},
"city.bulkDelete": {
"name": "city.bulkDelete",
"label": "Cities Bulk Delete",
"tableName": "city",
"isHidden": true
}
},
"apps": {
"greetingsApp": {
"name": "greetingsApp",
"label": "Greetings App",
"iconName": "emoji_people",
"widgets": [
"PersonsByCreateDateBarChart",
"QuickSightChartRenderer"
],
"children": [
{
"type": "PROCESS",
"name": "greet",
"label": "Greet People",
"iconName": "emoji_people"
},
{
"type": "TABLE",
"name": "person",
"label": "Person",
"iconName": "person"
},
{
"type": "TABLE",
"name": "city",
"label": "Cities",
"iconName": "location_city"
},
{
"type": "PROCESS",
"name": "greetInteractive",
"label": "Greet Interactive",
"iconName": "waving_hand"
}
],
"childMap": {
"greetInteractive": {
"type": "PROCESS",
"name": "greetInteractive",
"label": "Greet Interactive",
"iconName": "waving_hand"
},
"city": {
"type": "TABLE",
"name": "city",
"label": "Cities",
"iconName": "location_city"
},
"person": {
"type": "TABLE",
"name": "person",
"label": "Person",
"iconName": "person"
},
"greet": {
"type": "PROCESS",
"name": "greet",
"label": "Greet People",
"iconName": "emoji_people"
}
},
"sections": [
{
"name": "greetingsApp",
"label": "Greetings App",
"icon": {
"name": "badge"
},
"tables": [
"person",
"city"
],
"processes": [
"greet",
"greetInteractive"
]
}
]
},
"peopleApp": {
"name": "peopleApp",
"label": "People App",
"iconName": "person",
"widgets": [],
"children": [
{
"type": "APP",
"name": "greetingsApp",
"label": "Greetings App",
"iconName": "emoji_people"
},
{
"type": "PROCESS",
"name": "clonePeople",
"label": "Clone People",
"iconName": "content_copy"
}
],
"childMap": {
"greetingsApp": {
"type": "APP",
"name": "greetingsApp",
"label": "Greetings App",
"iconName": "emoji_people"
},
"clonePeople": {
"type": "PROCESS",
"name": "clonePeople",
"label": "Clone People",
"iconName": "content_copy"
}
},
"sections": [
{
"name": "peopleApp",
"label": "People App",
"icon": {
"name": "badge"
},
"processes": [
"clonePeople"
]
}
]
},
"miscellaneous": {
"name": "miscellaneous",
"label": "Miscellaneous",
"iconName": "stars",
"widgets": [],
"children": [
{
"type": "TABLE",
"name": "carrier",
"label": "Carrier",
"iconName": "local_shipping"
},
{
"type": "PROCESS",
"name": "simpleSleep",
"label": "Simple Sleep"
},
{
"type": "PROCESS",
"name": "sleepInteractive",
"label": "Sleep Interactive"
},
{
"type": "PROCESS",
"name": "simpleThrow",
"label": "Simple Throw"
}
],
"childMap": {
"carrier": {
"type": "TABLE",
"name": "carrier",
"label": "Carrier",
"iconName": "local_shipping"
},
"simpleSleep": {
"type": "PROCESS",
"name": "simpleSleep",
"label": "Simple Sleep"
},
"simpleThrow": {
"type": "PROCESS",
"name": "simpleThrow",
"label": "Simple Throw"
},
"sleepInteractive": {
"type": "PROCESS",
"name": "sleepInteractive",
"label": "Sleep Interactive"
}
},
"sections": [
{
"name": "miscellaneous",
"label": "Miscellaneous",
"icon": {
"name": "badge"
},
"tables": [
"carrier"
],
"processes": [
"simpleSleep",
"sleepInteractive",
"simpleThrow"
]
}
]
}
},
"appTree": [
{
"type": "APP",
"name": "peopleApp",
"label": "People App",
"children": [
{
"type": "APP",
"name": "greetingsApp",
"label": "Greetings App",
"children": [
{
"type": "PROCESS",
"name": "greet",
"label": "Greet People",
"iconName": "emoji_people"
},
{
"type": "TABLE",
"name": "person",
"label": "Person",
"iconName": "person"
},
{
"type": "TABLE",
"name": "city",
"label": "Cities",
"iconName": "location_city"
},
{
"type": "PROCESS",
"name": "greetInteractive",
"label": "Greet Interactive",
"iconName": "waving_hand"
}
],
"iconName": "emoji_people"
},
{
"type": "PROCESS",
"name": "clonePeople",
"label": "Clone People",
"iconName": "content_copy"
}
],
"iconName": "person"
},
{
"type": "APP",
"name": "miscellaneous",
"label": "Miscellaneous",
"children": [
{
"type": "TABLE",
"name": "carrier",
"label": "Carrier",
"iconName": "local_shipping"
},
{
"type": "PROCESS",
"name": "simpleSleep",
"label": "Simple Sleep"
},
{
"type": "PROCESS",
"name": "sleepInteractive",
"label": "Sleep Interactive"
},
{
"type": "PROCESS",
"name": "simpleThrow",
"label": "Simple Throw"
}
],
"iconName": "stars"
}
],
"branding": {
"logo": "/kr-logo.png",
"icon": "/kr-icon.png"
},
"widgets": {
"parcelTrackingDetails": {
"name": "parcelTrackingDetails",
"label": "Tracking Details",
"type": "childRecordList"
},
"deposcoSalesOrderLineItems": {
"name": "deposcoSalesOrderLineItems",
"label": "Line Items",
"type": "childRecordList"
},
"TotalShipmentsByDayBarChart": {
"name": "TotalShipmentsByDayBarChart",
"label": "Total Shipments By Day",
"type": "chart"
},
"TotalShipmentsByMonthLineChart": {
"name": "TotalShipmentsByMonthLineChart",
"label": "Total Shipments By Month",
"type": "chart"
},
"YTDShipmentsByCarrierPieChart": {
"name": "YTDShipmentsByCarrierPieChart",
"label": "Shipments By Carrier Year To Date",
"type": "chart"
},
"TodaysShipmentsStatisticsCard": {
"name": "TodaysShipmentsStatisticsCard",
"label": "Today's Shipments",
"type": "statistics"
},
"ShipmentsInTransitStatisticsCard": {
"name": "ShipmentsInTransitStatisticsCard",
"label": "Shipments In Transit",
"type": "statistics"
},
"OpenOrdersStatisticsCard": {
"name": "OpenOrdersStatisticsCard",
"label": "Open Orders",
"type": "statistics"
},
"ShippingExceptionsStatisticsCard": {
"name": "ShippingExceptionsStatisticsCard",
"label": "Shipping Exceptions",
"type": "statistics"
},
"WarehouseLocationCards": {
"name": "WarehouseLocationCards",
"type": "location"
},
"TotalShipmentsStatisticsCard": {
"name": "TotalShipmentsStatisticsCard",
"label": "Total Shipments",
"type": "statistics"
},
"SuccessfulDeliveriesStatisticsCard": {
"name": "SuccessfulDeliveriesStatisticsCard",
"label": "Successful Deliveries",
"type": "statistics"
},
"ServiceFailuresStatisticsCard": {
"name": "ServiceFailuresStatisticsCard",
"label": "Service Failures",
"type": "statistics"
},
"CarrierVolumeLineChart": {
"name": "CarrierVolumeLineChart",
"label": "Carrier Volume By Month",
"type": "lineChart"
},
"YTDSpendByCarrierTable": {
"name": "YTDSpendByCarrierTable",
"label": "Spend By Carrier Year To Date",
"type": "table"
},
"TimeInTransitBarChart": {
"name": "TimeInTransitBarChart",
"label": "Time In Transit Last 30 Days",
"type": "chart"
},
"OpenBillingWorksheetsTable": {
"name": "OpenBillingWorksheetsTable",
"label": "Open Billing Worksheets",
"type": "table"
},
"AssociatedParcelInvoicesTable": {
"name": "AssociatedParcelInvoicesTable",
"label": "Associated Parcel Invoices",
"type": "table",
"icon": "receipt"
},
"BillingWorksheetLinesTable": {
"name": "BillingWorksheetLinesTable",
"label": "Billing Worksheet Lines",
"type": "table"
},
"RatingIssuesWidget": {
"name": "RatingIssuesWidget",
"label": "Rating Issues",
"type": "html",
"icon": "warning",
"gridColumns": 6
},
"UnassignedParcelInvoicesTable": {
"name": "UnassignedParcelInvoicesTable",
"label": "Unassigned Parcel Invoices",
"type": "table"
},
"ParcelInvoiceSummaryWidget": {
"name": "ParcelInvoiceSummaryWidget",
"label": "Parcel Invoice Summary",
"type": "multiStatistics"
},
"ParcelInvoiceLineExceptionsSummaryWidget": {
"name": "ParcelInvoiceLineExceptionsSummaryWidget",
"label": "Parcel Invoice Line Exceptions",
"type": "multiStatistics"
},
"BillingWorksheetStatusStepper": {
"name": "BillingWorksheetStatusStepper",
"label": "Billing Worksheet Progress",
"type": "stepper",
"icon": "refresh",
"gridColumns": 6
},
"PersonsByCreateDateBarChart": {
"name": "PersonsByCreateDateBarChart",
"label": "Persons By Create Date",
"type": "barChart"
},
"QuickSightChartRenderer": {
"name": "QuickSightChartRenderer",
"label": "Quick Sight",
"type": "quickSightChart"
}
}
} }

View File

@ -27,7 +27,8 @@
"backendName": "first_name", "backendName": "first_name",
"type": "STRING", "type": "STRING",
"isRequired": true, "isRequired": true,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
}, },
{ {
"name": "lastName", "name": "lastName",
@ -35,7 +36,8 @@
"backendName": "last_name", "backendName": "last_name",
"type": "STRING", "type": "STRING",
"isRequired": true, "isRequired": true,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
}, },
{ {
"name": "birthDate", "name": "birthDate",
@ -43,14 +45,44 @@
"backendName": "birth_date", "backendName": "birth_date",
"type": "DATE", "type": "DATE",
"isRequired": false, "isRequired": false,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
}, },
{ {
"name": "email", "name": "email",
"label": "Email", "label": "Email",
"backendName": "email",
"type": "STRING", "type": "STRING",
"isRequired": false, "isRequired": false,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
},
{
"name": "isEmployed",
"label": "Is Employed",
"backendName": "is_employed",
"type": "BOOLEAN",
"isRequired": false,
"isEditable": true,
"displayFormat": "%s"
},
{
"name": "annualSalary",
"label": "Annual Salary",
"backendName": "annual_salary",
"type": "DECIMAL",
"isRequired": false,
"isEditable": true,
"displayFormat": "$%,.2f"
},
{
"name": "daysWorked",
"label": "Days Worked",
"backendName": "days_worked",
"type": "INTEGER",
"isRequired": false,
"isEditable": true,
"displayFormat": "%,d"
} }
] ]
}, },
@ -60,19 +92,7 @@
"stepType": "frontend", "stepType": "frontend",
"components": [ "components": [
{ {
"type": "HELP_TEXT", "type": "VALIDATION_REVIEW_SCREEN"
"values": {
"text": "The records below will be updated if you click Submit."
}
}
],
"viewFields": [
{
"name": "valuesBeingUpdated",
"label": "Values Being Updated",
"type": "STRING",
"isRequired": false,
"isEditable": true
} }
], ],
"recordListFields": [ "recordListFields": [
@ -82,7 +102,8 @@
"backendName": "first_name", "backendName": "first_name",
"type": "STRING", "type": "STRING",
"isRequired": true, "isRequired": true,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
}, },
{ {
"name": "lastName", "name": "lastName",
@ -90,7 +111,8 @@
"backendName": "last_name", "backendName": "last_name",
"type": "STRING", "type": "STRING",
"isRequired": true, "isRequired": true,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
}, },
{ {
"name": "birthDate", "name": "birthDate",
@ -98,83 +120,54 @@
"backendName": "birth_date", "backendName": "birth_date",
"type": "DATE", "type": "DATE",
"isRequired": false, "isRequired": false,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
}, },
{ {
"name": "email", "name": "email",
"label": "Email", "label": "Email",
"backendName": "email",
"type": "STRING", "type": "STRING",
"isRequired": false, "isRequired": false,
"isEditable": true "isEditable": true,
"displayFormat": "%s"
},
{
"name": "isEmployed",
"label": "Is Employed",
"backendName": "is_employed",
"type": "BOOLEAN",
"isRequired": false,
"isEditable": true,
"displayFormat": "%s"
},
{
"name": "annualSalary",
"label": "Annual Salary",
"backendName": "annual_salary",
"type": "DECIMAL",
"isRequired": false,
"isEditable": true,
"displayFormat": "$%,.2f"
},
{
"name": "daysWorked",
"label": "Days Worked",
"backendName": "days_worked",
"type": "INTEGER",
"isRequired": false,
"isEditable": true,
"displayFormat": "%,d"
} }
] ]
}, },
{ {
"name": "results", "name": "result",
"label": "Results", "label": "Result",
"stepType": "frontend", "stepType": "frontend",
"components": [ "components": [
{ {
"type": "HELP_TEXT", "type": "PROCESS_SUMMARY_RESULTS"
"values": {
"text": "The records below have been updated."
}
}
],
"recordListFields": [
{
"name": "id",
"label": "Id",
"type": "INTEGER",
"isRequired": false,
"isEditable": false
},
{
"name": "createDate",
"label": "Create Date",
"backendName": "create_date",
"type": "DATE_TIME",
"isRequired": false,
"isEditable": false
},
{
"name": "modifyDate",
"label": "Modify Date",
"backendName": "modify_date",
"type": "DATE_TIME",
"isRequired": false,
"isEditable": false
},
{
"name": "firstName",
"label": "First Name",
"backendName": "first_name",
"type": "STRING",
"isRequired": true,
"isEditable": true
},
{
"name": "lastName",
"label": "Last Name",
"backendName": "last_name",
"type": "STRING",
"isRequired": true,
"isEditable": true
},
{
"name": "birthDate",
"label": "Birth Date",
"backendName": "birth_date",
"type": "DATE",
"isRequired": false,
"isEditable": true
},
{
"name": "email",
"label": "Email",
"type": "STRING",
"isRequired": false,
"isEditable": true
} }
] ]
} }

View File

@ -0,0 +1,155 @@
{
"table": {
"name": "person",
"label": "Person",
"isHidden": false,
"primaryKeyField": "id",
"iconName": "person",
"fields": {
"firstName": {
"name": "firstName",
"label": "First Name",
"type": "STRING",
"isRequired": true,
"isEditable": true,
"displayFormat": "%s"
},
"lastName": {
"name": "lastName",
"label": "Last Name",
"type": "STRING",
"isRequired": true,
"isEditable": true,
"displayFormat": "%s"
},
"annualSalary": {
"name": "annualSalary",
"label": "Annual Salary",
"type": "DECIMAL",
"isRequired": false,
"isEditable": true,
"displayFormat": "$%,.2f"
},
"modifyDate": {
"name": "modifyDate",
"label": "Modify Date",
"type": "DATE_TIME",
"isRequired": false,
"isEditable": false,
"displayFormat": "%s"
},
"daysWorked": {
"name": "daysWorked",
"label": "Days Worked",
"type": "INTEGER",
"isRequired": false,
"isEditable": true,
"displayFormat": "%,d"
},
"id": {
"name": "id",
"label": "Id",
"type": "INTEGER",
"isRequired": false,
"isEditable": false,
"displayFormat": "%s"
},
"birthDate": {
"name": "birthDate",
"label": "Birth Date",
"type": "DATE",
"isRequired": false,
"isEditable": true,
"displayFormat": "%s"
},
"isEmployed": {
"name": "isEmployed",
"label": "Is Employed",
"type": "BOOLEAN",
"isRequired": false,
"isEditable": true,
"displayFormat": "%s"
},
"email": {
"name": "email",
"label": "Email",
"type": "STRING",
"isRequired": false,
"isEditable": true,
"displayFormat": "%s"
},
"createDate": {
"name": "createDate",
"label": "Create Date",
"type": "DATE_TIME",
"isRequired": false,
"isEditable": false,
"displayFormat": "%s"
}
},
"sections": [
{
"name": "identity",
"label": "Identity",
"tier": "T1",
"fieldNames": [
"id",
"firstName",
"lastName"
],
"icon": {
"name": "badge"
},
"isHidden": false
},
{
"name": "basicInfo",
"label": "Basic Info",
"tier": "T2",
"fieldNames": [
"email",
"birthDate"
],
"icon": {
"name": "dataset"
},
"isHidden": false
},
{
"name": "employmentInfo",
"label": "Employment Info",
"tier": "T2",
"fieldNames": [
"isEmployed",
"annualSalary",
"daysWorked"
],
"icon": {
"name": "work"
},
"isHidden": false
},
{
"name": "dates",
"label": "Dates",
"tier": "T3",
"fieldNames": [
"createDate",
"modifyDate"
],
"icon": {
"name": "calendar_month"
},
"isHidden": false
}
],
"capabilities": [
"TABLE_COUNT",
"TABLE_GET",
"TABLE_QUERY",
"TABLE_DELETE",
"TABLE_INSERT",
"TABLE_UPDATE"
]
}
}

View File

@ -0,0 +1,3 @@
[
{}
]

View File

@ -0,0 +1 @@
{}

View File

@ -35,3 +35,7 @@
// } // }
// } // }
// } // }
import {registerCommand} from "cypress-wait-for-stable-dom";
registerCommand({pollInterval: 100, timeout: 3000});

Binary file not shown.

View File

@ -13,7 +13,7 @@
"@fullcalendar/interaction": "5.10.0", "@fullcalendar/interaction": "5.10.0",
"@fullcalendar/react": "5.10.0", "@fullcalendar/react": "5.10.0",
"@fullcalendar/timegrid": "5.10.0", "@fullcalendar/timegrid": "5.10.0",
"@kingsrook/qqq-frontend-core": "1.0.35", "@kingsrook/qqq-frontend-core": "1.0.36",
"@mui/icons-material": "5.4.1", "@mui/icons-material": "5.4.1",
"@mui/material": "5.4.1", "@mui/material": "5.4.1",
"@mui/styled-engine": "5.4.1", "@mui/styled-engine": "5.4.1",
@ -105,7 +105,8 @@
"@types/uuid": "8.3.4", "@types/uuid": "8.3.4",
"@typescript-eslint/eslint-plugin": "5.10.2", "@typescript-eslint/eslint-plugin": "5.10.2",
"@typescript-eslint/parser": "5.10.2", "@typescript-eslint/parser": "5.10.2",
"cypress": "10.3.1", "cypress": "11.0.1",
"cypress-wait-for-stable-dom": "0.1.0",
"eslint": "8.8.0", "eslint": "8.8.0",
"eslint-config-airbnb": "19.0.4", "eslint-config-airbnb": "19.0.4",
"eslint-import-resolver-typescript": "2.5.0", "eslint-import-resolver-typescript": "2.5.0",

View File

@ -23,6 +23,7 @@ import {useAuth0} from "@auth0/auth0-react";
import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException"; import {QException} from "@kingsrook/qqq-frontend-core/lib/exceptions/QException";
import {QAppNodeType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppNodeType"; import {QAppNodeType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppNodeType";
import {QAppTreeNode} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppTreeNode"; import {QAppTreeNode} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAppTreeNode";
import {QAuthenticationMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAuthenticationMetaData";
import {QBrandingMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QBrandingMetaData"; import {QBrandingMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QBrandingMetaData";
import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import CssBaseline from "@mui/material/CssBaseline"; import CssBaseline from "@mui/material/CssBaseline";
@ -86,6 +87,7 @@ function getStaticRoutes()
]; ];
} }
const qController = QClient.getInstance();
export const SESSION_ID_COOKIE_NAME = "sessionId"; export const SESSION_ID_COOKIE_NAME = "sessionId";
LicenseInfo.setLicenseKey(process.env.REACT_APP_MATERIAL_UI_LICENSE_KEY); LicenseInfo.setLicenseKey(process.env.REACT_APP_MATERIAL_UI_LICENSE_KEY);
@ -105,24 +107,51 @@ export default function App()
return; return;
} }
setLoadingToken(true); setLoadingToken(true);
(async () => (async () =>
{ {
try const authenticationMetaData: QAuthenticationMetaData = await qController.getAuthenticationMetaData();
if (authenticationMetaData.type === "AUTH_0")
{ {
console.log("Loading token..."); /////////////////////////////////////////
await getAccessTokenSilently(); // use auth0 if auth type is ... auth0 //
const idToken = await getIdTokenClaims(); /////////////////////////////////////////
setCookie(SESSION_ID_COOKIE_NAME, idToken.__raw, {path: "/"}); try
setIsFullyAuthenticated(true); {
console.log("Token load complete."); console.log("Loading token...");
await getAccessTokenSilently();
const idToken = await getIdTokenClaims();
setCookie(SESSION_ID_COOKIE_NAME, idToken.__raw, {path: "/"});
setIsFullyAuthenticated(true);
console.log("Token load complete.");
}
catch (e)
{
console.log(`Error loading token: ${JSON.stringify(e)}`);
removeCookie(SESSION_ID_COOKIE_NAME);
qController.clearAuthenticationMetaDataLocalStorage();
logout();
return;
}
} }
catch (e) else if (authenticationMetaData.type === "FULLY_ANONYMOUS" || authenticationMetaData.type === "MOCK")
{ {
console.log(`Error loading token: ${JSON.stringify(e)}`); /////////////////////////////////////////////
removeCookie(SESSION_ID_COOKIE_NAME); // use a random token if anonymous or mock //
logout(); /////////////////////////////////////////////
console.log("Generating random token...");
setIsFullyAuthenticated(true);
setCookie(SESSION_ID_COOKIE_NAME, Md5.hashStr(`${new Date()}`), {path: "/"});
console.log("Token generation complete.");
return; return;
} }
else
{
console.log(`Unrecognized authenticationMetaData.type: ${authenticationMetaData.type}`);
qController.clearAuthenticationMetaDataLocalStorage();
}
})(); })();
}, [loadingToken]); }, [loadingToken]);
@ -265,7 +294,7 @@ export default function App()
routeList.push({ routeList.push({
name: `${app.label}`, name: `${app.label}`,
key: `${app.name}.dev`, key: `${app.name}.record.dev`,
route: `${path}/:id/dev`, route: `${path}/:id/dev`,
component: <EntityDeveloperView table={table} />, component: <EntityDeveloperView table={table} />,
}); });
@ -342,13 +371,13 @@ export default function App()
let profileRoutes = {}; let profileRoutes = {};
const gravatarBase = "https://www.gravatar.com/avatar/"; const gravatarBase = "https://www.gravatar.com/avatar/";
const hash = Md5.hashStr(user.email); const hash = Md5.hashStr(user?.email || "user");
const profilePicture = `${gravatarBase}${hash}`; const profilePicture = `${gravatarBase}${hash}`;
profileRoutes = { profileRoutes = {
type: "collapse", type: "collapse",
name: user.name, name: user?.name,
key: user.name, key: "username",
icon: <MDAvatar src={profilePicture} alt="{user.name}" size="sm" />, icon: <MDAvatar src={profilePicture} alt="{user?.name}" size="sm" />,
collapse: [ collapse: [
{ {
name: "My Profile", name: "My Profile",
@ -388,11 +417,16 @@ export default function App()
} }
catch (e) catch (e)
{ {
console.error(e);
if (e instanceof QException) if (e instanceof QException)
{ {
if ((e as QException).message.indexOf("status code 401") !== -1) if ((e as QException).message.indexOf("status code 401") !== -1)
{ {
removeCookie(SESSION_ID_COOKIE_NAME); removeCookie(SESSION_ID_COOKIE_NAME);
//////////////////////////////////////////////////////
// todo - this is auth0 logout... make more generic //
//////////////////////////////////////////////////////
logout(); logout();
return; return;
} }

View File

@ -19,11 +19,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {Auth0Provider, useAuth0} from "@auth0/auth0-react"; import {useAuth0} from "@auth0/auth0-react";
import React, {useEffect} from "react"; import React, {useEffect} from "react";
import {useCookies} from "react-cookie"; import {useCookies} from "react-cookie";
import {SESSION_ID_COOKIE_NAME} from "App"; import {SESSION_ID_COOKIE_NAME} from "App";
import {AUTH0_CLIENT_ID, AUTH0_DOMAIN} from "index";
interface Props interface Props
{ {
@ -44,11 +43,7 @@ function HandleAuthorizationError({errorMessage}: Props)
}); });
return ( return (
<Auth0Provider domain={AUTH0_DOMAIN} clientId={AUTH0_CLIENT_ID}> <div>{errorMessage}</div>
<div>
<div>{errorMessage}</div>
</div>
</Auth0Provider>
); );
} }

View File

@ -20,6 +20,7 @@
*/ */
import {Auth0Provider} from "@auth0/auth0-react"; import {Auth0Provider} from "@auth0/auth0-react";
import {QAuthenticationMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QAuthenticationMetaData";
import React from "react"; import React from "react";
import {render} from "react-dom"; import {render} from "react-dom";
import {BrowserRouter, useNavigate, useSearchParams} from "react-router-dom"; import {BrowserRouter, useNavigate, useSearchParams} from "react-router-dom";
@ -28,52 +29,73 @@ import "qqq/styles/qqq-override-styles.css";
import {MaterialUIControllerProvider} from "context"; import {MaterialUIControllerProvider} from "context";
import HandleAuthorizationError from "HandleAuthorizationError"; import HandleAuthorizationError from "HandleAuthorizationError";
import ProtectedRoute from "qqq/auth0/protected-route"; import ProtectedRoute from "qqq/auth0/protected-route";
import QClient from "qqq/utils/QClient";
export const AUTH0_DOMAIN = process.env.REACT_APP_AUTH0_DOMAIN; const qController = QClient.getInstance();
export const AUTH0_CLIENT_ID = process.env.REACT_APP_AUTH0_CLIENT_ID; const authenticationMetaDataPromise: Promise<QAuthenticationMetaData> = qController.getAuthenticationMetaData()
// @ts-ignore authenticationMetaDataPromise.then((authenticationMetaData) =>
function Auth0ProviderWithRedirectCallback({children, ...props})
{ {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
// @ts-ignore // @ts-ignore
const onRedirectCallback = (appState) => function Auth0ProviderWithRedirectCallback({children, ...props})
{ {
navigate((appState && appState.returnTo) || window.location.pathname); const navigate = useNavigate();
}; const [searchParams] = useSearchParams();
if (searchParams.get("error"))
// @ts-ignore
const onRedirectCallback = (appState) =>
{
navigate((appState && appState.returnTo) || window.location.pathname);
};
if (searchParams.get("error"))
{
return (
// @ts-ignore
<Auth0Provider {...props}>
<HandleAuthorizationError errorMessage={searchParams.get("error_description")} />
</Auth0Provider>
);
}
else
{
return (
// @ts-ignore
<Auth0Provider onRedirectCallback={onRedirectCallback} {...props}>
{children}
</Auth0Provider>
);
}
}
if (authenticationMetaData.type === "AUTH_0")
{ {
return ( const domain = process.env.REACT_APP_AUTH0_DOMAIN;
// @ts-ignore const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
<Auth0Provider {...props}>
<HandleAuthorizationError errorMessage={searchParams.get("error_description")} /> render(
</Auth0Provider> <BrowserRouter>
<Auth0ProviderWithRedirectCallback
domain={domain}
clientId={clientId}
redirectUri={`${window.location.origin}/dashboards/overview`}
>
<MaterialUIControllerProvider>
<ProtectedRoute component={App} />
</MaterialUIControllerProvider>
</Auth0ProviderWithRedirectCallback>
</BrowserRouter>,
document.getElementById("root"),
); );
} }
else else
{ {
return ( render(
// @ts-ignore <BrowserRouter>
<Auth0Provider onRedirectCallback={onRedirectCallback} {...props}> <MaterialUIControllerProvider>
{children} <App />
</Auth0Provider> </MaterialUIControllerProvider>
); </BrowserRouter>
, document.getElementById("root"));
} }
}
render( })
<BrowserRouter>
<Auth0ProviderWithRedirectCallback
domain={AUTH0_DOMAIN}
clientId={AUTH0_CLIENT_ID}
redirectUri={`${window.location.origin}/dashboards/overview`}
>
<MaterialUIControllerProvider>
<ProtectedRoute component={App} />
</MaterialUIControllerProvider>
</Auth0ProviderWithRedirectCallback>
</BrowserRouter>,
document.getElementById("root"),
);

View File

@ -19,12 +19,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import {AdornmentType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/AdornmentType";
import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability"; import {Capability} from "@kingsrook/qqq-frontend-core/lib/model/metaData/Capability";
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData"; import {QProcessMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria"; import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterCriteria";
import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy"; import {QFilterOrderBy} from "@kingsrook/qqq-frontend-core/lib/model/query/QFilterOrderBy";
import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter"; import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryFilter";
@ -44,10 +41,9 @@ import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem"; import MenuItem from "@mui/material/MenuItem";
import Modal from "@mui/material/Modal"; import Modal from "@mui/material/Modal";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
import {DataGridPro, getGridDateOperators, GridCallbackDetails, GridColDef, GridColumnOrderChangeParams, GridColumnVisibilityModel, GridDensity, GridEventListener, GridExportMenuItemProps, GridFilterModel, GridLinkOperator, GridPinnedColumns, gridPreferencePanelStateSelector, GridRowId, GridRowParams, GridRowsProp, GridSelectionModel, GridSortItem, GridSortModel, GridState, GridToolbarColumnsButton, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarExportContainer, GridToolbarFilterButton, MuiEvent, useGridApiContext, useGridApiEventHandler, useGridSelector} from "@mui/x-data-grid-pro"; import {DataGridPro, GridCallbackDetails, GridColDef, GridColumnOrderChangeParams, GridColumnVisibilityModel, GridDensity, GridEventListener, GridExportMenuItemProps, GridFilterModel, GridLinkOperator, GridPinnedColumns, gridPreferencePanelStateSelector, GridRowId, GridRowParams, GridRowsProp, GridSelectionModel, GridSortItem, GridSortModel, GridState, GridToolbarColumnsButton, GridToolbarContainer, GridToolbarDensitySelector, GridToolbarExportContainer, GridToolbarFilterButton, MuiEvent, useGridApiContext, useGridApiEventHandler, useGridSelector} from "@mui/x-data-grid-pro";
import {GridFilterOperator} from "@mui/x-data-grid/models/gridFilterOperator";
import React, {useContext, useEffect, useReducer, useRef, useState} from "react"; import React, {useContext, useEffect, useReducer, useRef, useState} from "react";
import {Link, useLocation, useNavigate, useSearchParams} from "react-router-dom"; import {useLocation, useNavigate, useSearchParams} from "react-router-dom";
import QContext from "QContext"; import QContext from "QContext";
import DashboardLayout from "qqq/components/DashboardLayout"; import DashboardLayout from "qqq/components/DashboardLayout";
import Footer from "qqq/components/Footer"; import Footer from "qqq/components/Footer";
@ -55,7 +51,6 @@ import Navbar from "qqq/components/Navbar";
import {QActionsMenuButton, QCreateNewButton} from "qqq/components/QButtons"; import {QActionsMenuButton, QCreateNewButton} from "qqq/components/QButtons";
import MDAlert from "qqq/components/Temporary/MDAlert"; import MDAlert from "qqq/components/Temporary/MDAlert";
import MDBox from "qqq/components/Temporary/MDBox"; import MDBox from "qqq/components/Temporary/MDBox";
import {buildQGridPvsOperators, QGridBooleanOperators, QGridNumericOperators, QGridStringOperators} from "qqq/pages/entity-list/QGridFilterOperators";
import ProcessRun from "qqq/pages/process-run"; import ProcessRun from "qqq/pages/process-run";
import DataGridUtils from "qqq/utils/DataGridUtils"; import DataGridUtils from "qqq/utils/DataGridUtils";
import QClient from "qqq/utils/QClient"; import QClient from "qqq/utils/QClient";
@ -237,7 +232,7 @@ function EntityList({table, launchProcess}: Props): JSX.Element
const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData); const [activeModalProcess, setActiveModalProcess] = useState(null as QProcessMetaData);
const [launchingProcess, setLaunchingProcess] = useState(launchProcess); const [launchingProcess, setLaunchingProcess] = useState(launchProcess);
const [recordIdsForProcess, setRecordIdsForProcess] = useState(null as string | QQueryFilter) const [recordIdsForProcess, setRecordIdsForProcess] = useState(null as string | QQueryFilter);
const instance = useRef({timer: null}); const instance = useRef({timer: null});
@ -355,13 +350,26 @@ function EntityList({table, launchProcess}: Props): JSX.Element
return qFilter; return qFilter;
}; };
const getTableMetaData = async (): Promise<QTableMetaData> =>
{
if(tableMetaData !== null)
{
return(new Promise((resolve) =>
{
resolve(tableMetaData)
}));
}
return (qController.loadTableMetaData(tableName));
}
const updateTable = () => const updateTable = () =>
{ {
setLoading(true); setLoading(true);
setRows([]); setRows([]);
(async () => (async () =>
{ {
const tableMetaData = await qController.loadTableMetaData(tableName); const tableMetaData = await getTableMetaData();
setPageHeader(tableMetaData.label); setPageHeader(tableMetaData.label);
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
@ -530,7 +538,7 @@ function EntityList({table, launchProcess}: Props): JSX.Element
const handlePinnedColumnsChange = (pinnedColumns: GridPinnedColumns) => const handlePinnedColumnsChange = (pinnedColumns: GridPinnedColumns) =>
{ {
setPinnedColumns(pinnedColumns) setPinnedColumns(pinnedColumns);
localStorage.setItem(pinnedColumnsLocalStorageKey, JSON.stringify(pinnedColumns)); localStorage.setItem(pinnedColumnsLocalStorageKey, JSON.stringify(pinnedColumns));
}; };
@ -1080,7 +1088,14 @@ function EntityList({table, launchProcess}: Props): JSX.Element
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
useEffect(() => useEffect(() =>
{ {
updateTable(); if(latestQueryId > 0)
{
////////////////////////////////////////////////////////////////////////////////////////
// to avoid both this useEffect and the one below from both doing an "initial query", //
// only run this one if at least 1 query has already been ran //
////////////////////////////////////////////////////////////////////////////////////////
updateTable();
}
}, [ pageNumber, rowsPerPage, columnSortModel ]); }, [ pageNumber, rowsPerPage, columnSortModel ]);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -32,6 +32,7 @@ class QClient
private static handleException(exception: QException) private static handleException(exception: QException)
{ {
// todo - check for 401 and clear cookie et al & logout?
console.log(`Caught Exception: ${JSON.stringify(exception)}`); console.log(`Caught Exception: ${JSON.stringify(exception)}`);
throw (exception); throw (exception);
} }

View File

@ -32,30 +32,36 @@ class QProcessUtils
public static getProcessesForTable(metaData: QInstance, tableName: string, includeHidden = false): QProcessMetaData[] public static getProcessesForTable(metaData: QInstance, tableName: string, includeHidden = false): QProcessMetaData[]
{ {
const matchingProcesses: QProcessMetaData[] = []; const matchingProcesses: QProcessMetaData[] = [];
const processKeys = [...metaData.processes.keys()]; if (metaData.processes)
processKeys.forEach((key) =>
{ {
const process = metaData.processes.get(key); const processKeys = [...metaData.processes.keys()];
if (process.tableName === tableName && (includeHidden || !process.isHidden)) processKeys.forEach((key) =>
{ {
matchingProcesses.push(process); const process = metaData.processes.get(key);
} if (process.tableName === tableName && (includeHidden || !process.isHidden))
}); {
matchingProcesses.push(process);
}
});
}
return matchingProcesses; return matchingProcesses;
} }
public static getReportsForTable(metaData: QInstance, tableName: string, includeHidden = false): QReportMetaData[] public static getReportsForTable(metaData: QInstance, tableName: string, includeHidden = false): QReportMetaData[]
{ {
const matchingReports: QReportMetaData[] = []; const matchingReports: QReportMetaData[] = [];
const reportKeys = [...metaData.reports.keys()]; if (metaData.reports)
reportKeys.forEach((key) =>
{ {
const process = metaData.reports.get(key); const reportKeys = [...metaData.reports.keys()];
if (process.tableName === tableName) reportKeys.forEach((key) =>
{ {
matchingReports.push(process); const process = metaData.reports.get(key);
} if (process.tableName === tableName)
}); {
matchingReports.push(process);
}
});
}
return matchingReports; return matchingReports;
} }