DetailsList implemented

This commit is contained in:
vaidankarswapnil 2021-07-29 12:15:21 +05:30
parent 754f0b392c
commit 4f632b234f
4 changed files with 255 additions and 140 deletions

View File

@ -25,6 +25,7 @@ abstract class DataTableViewModel {
/* Observables */ /* Observables */
public items = ko.observableArray<Entities.ITableEntity>(); public items = ko.observableArray<Entities.ITableEntity>();
public items1: Entities.ITableEntity[];
public selected = ko.observableArray<Entities.ITableEntity>(); public selected = ko.observableArray<Entities.ITableEntity>();
public table: DataTables.DataTable; public table: DataTables.DataTable;
@ -54,6 +55,7 @@ abstract class DataTableViewModel {
constructor() { constructor() {
this.items([]); this.items([]);
this.items1 = [];
this.selected([]); this.selected([]);
// Late bound // Late bound
this.dataTableOperationManager = null; this.dataTableOperationManager = null;
@ -172,36 +174,38 @@ abstract class DataTableViewModel {
} }
protected renderPage( protected renderPage(
renderCallBack: any, // renderCallBack: any,
draw: number, // draw: number,
startIndex: number, startIndex: number,
pageSize: number, pageSize: number
oSettings: any, // oSettings: any,
postRenderTasks: (startIndex: number, pageSize: number) => Promise<void> = null // postRenderTasks: (startIndex: number, pageSize: number) => Promise<void> = null
) { ) {
this.updatePaginationControls(oSettings); // this.updatePaginationControls(oSettings);
// pageSize < 0 means to show all data // pageSize < 0 means to show all data
var endIndex = pageSize < 0 ? this.cache.length : startIndex + pageSize; var endIndex = pageSize < 0 ? this.cache.length : startIndex + pageSize;
var renderData = this.cache.data.slice(startIndex, endIndex); var renderData = this.cache.data.slice(startIndex, endIndex);
this.items(renderData); this.items(renderData);
this.items1 = renderData;
console.log("🚀 ~ file: DataTableViewModel.ts ~ line 191 ~ DataTableViewModel ~ renderData", renderData); console.log("🚀 ~ file: DataTableViewModel.ts ~ line 191 ~ DataTableViewModel ~ renderData", renderData);
console.log("🚀 ~ file: DataTableViewModel.ts ~ line 192 ~ DataTableViewModel ~ this.items", this.items()); console.log("🚀 ~ file: DataTableViewModel.ts ~ line 192 ~ DataTableViewModel ~ this.items", this.items());
var render: IDataTableRenderData = { console.log("🚀 ~ file: DataTableViewModel.ts ~ line 192 ~ DataTableViewModel ~ this.items1", this.items1);
draw: draw, // var render: IDataTableRenderData = {
aaData: renderData, // draw: draw,
recordsTotal: this.cache.length, // aaData: renderData,
recordsFiltered: this.cache.length, // recordsTotal: this.cache.length,
}; // recordsFiltered: this.cache.length,
// };
if (!!postRenderTasks) { // if (!!postRenderTasks) {
postRenderTasks(startIndex, pageSize).then(() => { // postRenderTasks(startIndex, pageSize).then(() => {
this.table.rows().invalidate(); // this.table.rows().invalidate();
}); // });
} // }
renderCallBack(render); // renderCallBack(render);
if (this.queryTablesTab.onLoadStartKey != null && this.queryTablesTab.onLoadStartKey != undefined) { if (this.queryTablesTab.onLoadStartKey != null && this.queryTablesTab.onLoadStartKey != undefined) {
TelemetryProcessor.traceSuccess( TelemetryProcessor.traceSuccess(
Action.Tab, Action.Tab,

View File

@ -149,10 +149,10 @@ export default class TableEntityListViewModel extends DataTableViewModel {
public updateHeaders(newHeaders: string[], notifyColumnChanges: boolean = false, enablePrompt: boolean = true): void { public updateHeaders(newHeaders: string[], notifyColumnChanges: boolean = false, enablePrompt: boolean = true): void {
this.headers = newHeaders; this.headers = newHeaders;
if (notifyColumnChanges) { // if (notifyColumnChanges) {
this.clearSelection(); // this.clearSelection();
this.notifyColumnChanges(enablePrompt, this.queryTablesTab); // this.notifyColumnChanges(enablePrompt, this.queryTablesTab);
} // }
} }
/** /**
@ -162,7 +162,7 @@ export default class TableEntityListViewModel extends DataTableViewModel {
* fnCallback - is the render callback with data to render. * fnCallback - is the render callback with data to render.
* oSetting: current settings used for table initialization. * oSetting: current settings used for table initialization.
*/ */
public renderNextPageAndupdateCache(sSource: any, aoData: any, fnCallback: any, oSettings: any) { public renderNextPageAndupdateCache(sSource?: any, aoData?: any, fnCallback?: any, oSettings?: any): Promise<void> {
var tablePageSize: number; var tablePageSize: number;
var draw: number; var draw: number;
var prefetchNeeded = true; var prefetchNeeded = true;
@ -172,21 +172,21 @@ export default class TableEntityListViewModel extends DataTableViewModel {
var prefetchThreshold = 10; var prefetchThreshold = 10;
var tableQuery = this.tableQuery; var tableQuery = this.tableQuery;
for (var index in aoData) { // for (var index in aoData) {
var data = aoData[index]; // var data = aoData[index];
if (data.name === "length") { // if (data.name === "length") {
tablePageSize = data.value; // tablePageSize = data.value;
} // }
if (data.name === "start") { // if (data.name === "start") {
this.tablePageStartIndex = data.value; // this.tablePageStartIndex = data.value;
} // }
if (data.name === "draw") { // if (data.name === "draw") {
draw = data.value; // draw = data.value;
} // }
if (data.name === "order") { // if (data.name === "order") {
columnSortOrder = data.value; // columnSortOrder = data.value;
} // }
} // }
// Try cache if valid. // Try cache if valid.
if (this.isCacheValid(tableQuery)) { if (this.isCacheValid(tableQuery)) {
// Check if prefetch needed. // Check if prefetch needed.
@ -195,7 +195,7 @@ export default class TableEntityListViewModel extends DataTableViewModel {
if (columnSortOrder && (!this.cache.sortOrder || !_.isEqual(this.cache.sortOrder, columnSortOrder))) { if (columnSortOrder && (!this.cache.sortOrder || !_.isEqual(this.cache.sortOrder, columnSortOrder))) {
this.sortColumns(columnSortOrder, oSettings); this.sortColumns(columnSortOrder, oSettings);
} }
this.renderPage(fnCallback, draw, this.tablePageStartIndex, tablePageSize, oSettings); this.renderPage(this.tablePageStartIndex, tablePageSize);
if ( if (
!this.allDownloaded && !this.allDownloaded &&
this.tablePageStartIndex > 0 && // This is a case now that we can hit this as we re-construct table when we update column this.tablePageStartIndex > 0 && // This is a case now that we can hit this as we re-construct table when we update column
@ -218,11 +218,11 @@ export default class TableEntityListViewModel extends DataTableViewModel {
tablePageSize, tablePageSize,
downloadSize, downloadSize,
draw, draw,
fnCallback,
oSettings, oSettings,
columnSortOrder columnSortOrder
); );
} }
return undefined;
} }
public addEntityToCache(entity: Entities.ITableEntity): Q.Promise<any> { public addEntityToCache(entity: Entities.ITableEntity): Q.Promise<any> {
@ -402,7 +402,7 @@ export default class TableEntityListViewModel extends DataTableViewModel {
tablePageSize: number, tablePageSize: number,
downloadSize: number, downloadSize: number,
draw: number, draw: number,
renderCallBack: Function, // renderCallBack: Function,
oSettings: any, oSettings: any,
columnSortOrder: any columnSortOrder: any
): void { ): void {
@ -432,6 +432,10 @@ export default class TableEntityListViewModel extends DataTableViewModel {
userContext.apiType === "Cassandra" userContext.apiType === "Cassandra"
); );
var newHeaders: string[] = _.difference(selectedHeadersUnion, this.headers); var newHeaders: string[] = _.difference(selectedHeadersUnion, this.headers);
console.log(
"🚀 ~ file: TableEntityListViewModel.ts ~ line 435 ~ TableEntityListViewModel ~ .then ~ newHeaders",
newHeaders
);
if (newHeaders.length > 0) { if (newHeaders.length > 0) {
// Any new columns found will be added into headers array, which will trigger a re-render of the DataTable. // Any new columns found will be added into headers array, which will trigger a re-render of the DataTable.
// So there is no need to call it here. // So there is no need to call it here.
@ -440,8 +444,9 @@ export default class TableEntityListViewModel extends DataTableViewModel {
if (columnSortOrder) { if (columnSortOrder) {
this.sortColumns(columnSortOrder, oSettings); this.sortColumns(columnSortOrder, oSettings);
} }
this.renderPage(renderCallBack, draw, tablePageStartIndex, tablePageSize, oSettings); // this.renderPage(renderCallBack, draw, tablePageStartIndex, tablePageSize, oSettings);
} }
this.renderPage(0, 100);
} }
if (result.ExceedMaximumRetries) { if (result.ExceedMaximumRetries) {
@ -449,6 +454,10 @@ export default class TableEntityListViewModel extends DataTableViewModel {
} }
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(
"🚀 ~ file: TableEntityListViewModel.ts ~ line 452 ~ TableEntityListViewModel ~ //constructor ~ error",
error
);
const parsedErrors = parseError(error); const parsedErrors = parseError(error);
var errors = parsedErrors.map((error) => { var errors = parsedErrors.map((error) => {
return <ViewModels.QueryError>{ return <ViewModels.QueryError>{
@ -562,6 +571,10 @@ export default class TableEntityListViewModel extends DataTableViewModel {
} else { } else {
// Create cache. // Create cache.
this.cache.data = entities; this.cache.data = entities;
console.log(
"🚀 ~ file: TableEntityListViewModel.ts ~ line 569 ~ TableEntityListViewModel ~ .then ~ this.cache.data",
this.cache.data
);
} }
this.cache.tableQuery = tableQuery; this.cache.tableQuery = tableQuery;

View File

@ -160,7 +160,7 @@ export default class QueryViewModel {
notify: "always", notify: "always",
}); });
public runQuery = (): DataTables.DataTable => { public runQuery = (): void => {
let filter = this.setFilter(); let filter = this.setFilter();
if (filter && userContext.apiType !== "Cassandra") { if (filter && userContext.apiType !== "Cassandra") {
filter = filter.replace(/"/g, "'"); filter = filter.replace(/"/g, "'");
@ -175,7 +175,7 @@ export default class QueryViewModel {
this._tableEntityListViewModel.sqlQuery(this.setSqlFilter()); this._tableEntityListViewModel.sqlQuery(this.setSqlFilter());
this._tableEntityListViewModel.cqlQuery(filter); this._tableEntityListViewModel.cqlQuery(filter);
return this._tableEntityListViewModel.reloadTable(/*useSetting*/ false, /*resetHeaders*/ false); // return this._tableEntityListViewModel.reloadTable(/*useSetting*/ false, /*resetHeaders*/ false);
}; };
public clearQuery = (): DataTables.DataTable => { public clearQuery = (): DataTables.DataTable => {

View File

@ -1,3 +1,4 @@
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react";
import * as ko from "knockout"; import * as ko from "knockout";
import React, { Component } from "react"; import React, { Component } from "react";
import QueryInformation from "../../../../images//QueryBuilder/QueryInformation_16x.png"; import QueryInformation from "../../../../images//QueryBuilder/QueryInformation_16x.png";
@ -33,7 +34,11 @@ export interface Button {
enabled: boolean; enabled: boolean;
isSelected?: boolean; isSelected?: boolean;
} }
export interface IDocument {
partitionKey: string;
rowKey: string;
timeStamp: string;
}
export interface IQueryTablesTabComponentProps { export interface IQueryTablesTabComponentProps {
tabKind: ViewModels.CollectionTabKind; tabKind: ViewModels.CollectionTabKind;
title: string; title: string;
@ -58,6 +63,9 @@ interface IQueryTablesTabComponentStates {
editEntityButton: Button; editEntityButton: Button;
deleteEntityButton: Button; deleteEntityButton: Button;
isHelperActive: boolean; isHelperActive: boolean;
columns: IColumn[];
items: IDocument[];
isExpanded: boolean;
} }
class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, IQueryTablesTabComponentStates> { class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, IQueryTablesTabComponentStates> {
@ -86,9 +94,38 @@ class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, I
public valueLabel: string; public valueLabel: string;
public tableEntityListViewModel1: TableEntityListViewModel; public tableEntityListViewModel1: TableEntityListViewModel;
public tableEntityListViewModel2 = ko.observable<TableEntityListViewModel>(); public tableEntityListViewModel2 = ko.observable<TableEntityListViewModel>();
public allItems: IDocument[];
// public columns: IColumn[];
constructor(props: IQueryTablesTabComponentProps) { constructor(props: IQueryTablesTabComponentProps) {
super(props); super(props);
// this.columns = [];
const columns: IColumn[] = [
{
key: "column1",
name: "PartitionKey",
minWidth: 100,
maxWidth: 200,
data: String,
fieldName: "partitionKey",
// onRender: this.onRenderColumnItem,
},
{
key: "column2",
name: "RowKey",
minWidth: 100,
maxWidth: 200,
data: String,
fieldName: "rowKey",
},
{
key: "column3",
name: "Timestamp",
minWidth: 200,
maxWidth: 200,
data: String,
fieldName: "timeStamp",
},
];
this.container = props.collection && props.collection.container; this.container = props.collection && props.collection.container;
this.tableCommands = new TableCommands(this.container); this.tableCommands = new TableCommands(this.container);
this.tableDataClient = this.container.tableDataClient; this.tableDataClient = this.container.tableDataClient;
@ -146,6 +183,9 @@ class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, I
visible: true, visible: true,
isSelected: false, isSelected: false,
}, },
columns: columns,
items: [],
isExpanded: false,
}; };
this.state.tableEntityListViewModel.queryTablesTab = this.props.queryTablesTab; this.state.tableEntityListViewModel.queryTablesTab = this.props.queryTablesTab;
// console.log( // console.log(
@ -174,27 +214,73 @@ class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, I
this.valueLabel = this.state.queryViewModel.queryBuilderViewModel().valueLabel; this.valueLabel = this.state.queryViewModel.queryBuilderViewModel().valueLabel;
useCommandBar.getState().setContextButtons(this.getTabsButtons()); useCommandBar.getState().setContextButtons(this.getTabsButtons());
this.state.tableEntityListViewModel.items.subscribe(() => { // this.state.tableEntityListViewModel.items.subscribe(() => {
console.log( // console.log(
"🚀 ~ file: QueryTablesTab.tsx ~ line 54 ~ QueryTablesTab ~ sampleQuerySubscription ~ this.tableEntityListViewModel().items().length", // "🚀 ~ file: QueryTablesTab.tsx ~ line 54 ~ QueryTablesTab ~ sampleQuerySubscription ~ this.tableEntityListViewModel().items().length",
this.state.tableEntityListViewModel.items() // this.state.tableEntityListViewModel.items()
); // );
if (this.state.tableEntityListViewModel.items().length > 0 && userContext.apiType === "Tables") { // if (this.state.tableEntityListViewModel.items().length > 0 && userContext.apiType === "Tables") {
// this.state.queryViewModel.queryBuilderViewModel.setExample(); // // this.state.queryViewModel.queryBuilderViewModel.setExample();
// console.log( // // console.log(
// "🚀 ~ file: QueryTablesTab.tsx ~ line 55 ~ QueryTablesTab ~ sampleQuerySubscription ~ this.queryViewModel().queryBuilderViewModel().setExample()", // // "🚀 ~ file: QueryTablesTab.tsx ~ line 55 ~ QueryTablesTab ~ sampleQuerySubscription ~ this.queryViewModel().queryBuilderViewModel().setExample()",
// this.state.queryViewModel.queryBuilderViewModel.setExample() // // this.state.queryViewModel.queryBuilderViewModel.setExample()
// ); // // );
} // }
}); // });
this.props.queryTablesTab.container.tableDataClient.queryDocuments( // this.test();
this.props.queryTablesTab.collection, // this.state.tableEntityListViewModel.renderNextPageAndupdateCache();
"SELECT * FROM c", // setTimeout(() => {
true // console.log("items > ", this.state.tableEntityListViewModel.cache.data);
); // console.log("items > ", this.state.tableEntityListViewModel.items());
// console.log("items1 > ", this.state.tableEntityListViewModel.items1);
// console.log("items1 > simple > ", this.tableEntityListViewModel1.items1);
// this.allItems = this.generateDetailsList();
// this.setState({
// items: this.allItems,
// });
// // this.state = {
// // items: this.generateDetailsList()
// // }
// }, 10000);
// this.props.queryTablesTab.container.tableDataClient.queryDocuments(
// this.props.queryTablesTab.collection,
// "SELECT * FROM c",
// true
// );
this.buildCommandBarOptions(); this.buildCommandBarOptions();
} }
async componentDidMount(): Promise<void> {
const abc = await this.state.tableEntityListViewModel.renderNextPageAndupdateCache();
console.log(
"🚀 ~ file: QueryTablesTabComponent.tsx ~ line 249 ~ QueryTablesTabComponent ~ componentDidMount ~ abc",
abc
);
setTimeout(() => {
console.log("items > ", this.state.tableEntityListViewModel.cache.data);
console.log("items > ", this.state.tableEntityListViewModel.items());
console.log("items1 > ", this.state.tableEntityListViewModel.headers);
console.log("items1 > simple > ", this.tableEntityListViewModel1.items1);
// this.state.tableEntityListViewModel.headers.map(header => {
// })
this.allItems = this.generateDetailsList();
this.setState({
items: this.allItems,
});
// this.state = {
// items: this.generateDetailsList()
// }
}, 10000);
}
// public async test(): Promise<void> {
// await this.state.tableEntityListViewModel.renderNextPageAndupdateCache().then(() => {
// console.log("inside > ", this.state.tableEntityListViewModel.items());
// });
// console.log("items > ", this.state.tableEntityListViewModel.items());
// }
public onAddEntityClick = (): void => { public onAddEntityClick = (): void => {
useSidePanel useSidePanel
.getState() .getState()
@ -315,6 +401,32 @@ class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, I
this.props.tabsBaseInstance.updateNavbarWithTabsButtons(); this.props.tabsBaseInstance.updateNavbarWithTabsButtons();
} }
public generateDetailsList(): IDocument[] {
const items: IDocument[] = [];
this.state.tableEntityListViewModel.items().map((item) => {
console.log("generateDetailsList > ", item["PartitionKey"]._);
items.push({
partitionKey: item["PartitionKey"]._,
rowKey: item["RowKey"]._,
timeStamp: item["Timestamp"]._,
});
});
console.log(
"🚀 ~ file: QueryTablesTabComponent.tsx ~ line 383 ~ QueryTablesTabComponent ~ this.state.tableEntityListViewModel.items ~ items",
items
);
return items;
}
toggleAdvancedOptions(): void {
// console.log("toggleAdvancedOptions!");
this.setState({
isExpanded: !this.state.isExpanded,
});
this.state.queryViewModel.toggleAdvancedOptions();
}
render(): JSX.Element { render(): JSX.Element {
useCommandBar.getState().setContextButtons(this.getTabsButtons()); useCommandBar.getState().setContextButtons(this.getTabsButtons());
@ -411,96 +523,82 @@ class QueryTablesTabComponent extends Component<IQueryTablesTabComponentProps, I
</div> </div>
)} )}
<div className="advanced-options-panel"> <div className="advanced-options-panel">
<div className="advanced-heading"> <div className="advanced-heading" onClick={() => this.toggleAdvancedOptions()}>
<span <span
className="advanced-title" className="advanced-title"
role="button" role="button"
aria-expanded={this.state.isExpanded}
// onKeyDown = {() => this.state.queryViewModel.ontoggleAdvancedOptionsKeyDown}
// data-bind="click:toggleAdvancedOptions, event: { keydown: ontoggleAdvancedOptionsKeyDown }, attr:{ 'aria-expanded': isExpanded() ? 'true' : 'false' }" // data-bind="click:toggleAdvancedOptions, event: { keydown: ontoggleAdvancedOptionsKeyDown }, attr:{ 'aria-expanded': isExpanded() ? 'true' : 'false' }"
tabIndex={0} tabIndex={0}
> >
<div {!this.state.isExpanded && (
className="themed-images" <div className="themed-images" id="ExpandChevronRight">
// type="text/html" <img
id="ExpandChevronRight" className="imgiconwidth expand-triangle expand-triangle-right"
// data-bind="hasFocus: focusExpandIcon" src={TriangleRight}
> alt="toggle"
<img />
className="imgiconwidth expand-triangle expand-triangle-right" </div>
src={TriangleRight} )}
alt="toggle" {this.state.queryViewModel.isExpanded() && (
/> <div className="themed-images" id="ExpandChevronDown">
</div> <img className="imgiconwidth expand-triangle" src={TriangleDown} alt="toggle" />
<div </div>
className="themed-images" )}
// type="text/html"
id="ExpandChevronDown"
>
<img className="imgiconwidth expand-triangle" src={TriangleDown} alt="toggle" />
</div>
<span>Advanced Options</span> <span>Advanced Options</span>
</span> </span>
</div> </div>
<div {this.state.isExpanded && (
className="advanced-options" <div className="advanced-options">
// data-bind="visible: isExpanded" <div className="top">
> <span>Show top results:</span>
<div className="top"> <input
<span>Show top results:</span> className="top-input"
<input type="number"
className="top-input" title={this.state.queryViewModel.topValueLimitMessage}
type="number" // data-bind="hasFocus: focusTopResult, textInput: topValue, attr: { title: topValueLimitMessage }"
// data-bind="hasFocus: focusTopResult, textInput: topValue, attr: { title: topValueLimitMessage }" role="textbox"
role="textbox" aria-label="Show top results"
aria-label="Show top results"
/>
<div
role="alert"
aria-atomic="true"
className="inline-div"
// data-bind="visible: isExceedingLimit"
>
<img className="advanced-options-icon" src={StatusWraning} />
<span data-bind="text: topValueLimitMessage"></span>
</div>
</div>
<div className="select">
<span> Select fields for query: </span>
<div
// data-bind="visible: isSelected"
>
<img className="advanced-options-icon" src={QueryInformation} />
<span
className="select-options-text"
// data-bind="text: selectMessage"
/> />
{this.state.queryViewModel.isExceedingLimit() && (
<div role="alert" aria-atomic="true" className="inline-div">
<img className="advanced-options-icon" src={StatusWraning} />
<span>{this.state.queryViewModel.topValueLimitMessage}</span>
</div>
)}
</div>
<div className="select">
<span> Select fields for query: </span>
{this.state.queryViewModel.isSelected() && (
<div>
<img className="advanced-options-icon" src={QueryInformation} />
<span className="select-options-text">{this.state.queryViewModel.selectMessage()}</span>
</div>
)}
<a
className="select-options-link"
// data-bind="click: selectQueryOptions, event: { keydown: onselectQueryOptionsKeyDown }"
tabIndex={0}
role="link"
onClick={() => this.state.queryViewModel.selectQueryOptions()}
>
<span>Choose Columns... </span>
</a>
</div> </div>
<a
className="select-options-link"
// data-bind="click: selectQueryOptions, event: { keydown: onselectQueryOptionsKeyDown }"
tabIndex={0}
role="link"
>
<span>Choose Columns... </span>
</a>
</div> </div>
</div> )}
</div> </div>
</div> </div>
{this.state.tableEntityListViewModel.items().map((item, index) => (
<label key={index}>{item}</label> <div className="tablesQueryTab tableContainer">
))} <DetailsList
<div items={this.state.items}
className="tablesQueryTab tableContainer" columns={this.state.columns}
data-bind="with: tableEntityListViewModel, attr: { selectionMode={SelectionMode.none}
id: tableEntityListViewModel.id layoutMode={DetailsListLayoutMode.justified}
}" compact={true}
> />
<table
id="storageTable"
className="storage azure-table show-gridlines"
tabIndex={0}
data-bind="tableSource: items, tableSelection: selected"
></table>
</div> </div>
</div> </div>
); );