-
Notifications
You must be signed in to change notification settings - Fork 98
Use UI toolkit for variable table #291
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
Merged
fcollonval
merged 8 commits into
jupyterlab-contrib:main
from
kentarolim10:switch-to-jupyter-ui-toolkit
Dec 7, 2023
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
7c50518
Use UI toolkit for variable table
kentarolim10 823420f
Register web components
kentarolim10 da1654e
Merge branch 'master' of https://github.com/kentarolim10/jupyterlab-v…
kentarolim10 0060a6d
Integrate ui-toolkit library to filter variable
kentarolim10 ea94250
Convert tests to use ui-toolkit
kentarolim10 4fdade6
jlpm build
kentarolim10 e47583f
Make requested PR changes
kentarolim10 8cece5c
Fix select component
kentarolim10 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,12 +8,38 @@ import { DockLayout, Widget } from '@lumino/widgets'; | |
|
||
import { IVariableInspector } from './tokens'; | ||
|
||
import { | ||
DataGrid as WebDataGrid, | ||
DataGridRow, | ||
DataGridCell, | ||
provideJupyterDesignSystem, | ||
Select, | ||
Option, | ||
TextField, | ||
Button, | ||
jpDataGrid, | ||
jpDataGridRow, | ||
jpDataGridCell, | ||
jpTextField, | ||
jpOption, | ||
jpSelect, | ||
jpButton | ||
} from '@jupyter/web-components'; | ||
provideJupyterDesignSystem().register( | ||
jpDataGrid(), | ||
jpDataGridRow(), | ||
jpDataGridCell(), | ||
jpTextField(), | ||
jpOption(), | ||
jpSelect(), | ||
jpButton() | ||
); | ||
|
||
import wildcardMatch from 'wildcard-match'; | ||
|
||
const TITLE_CLASS = 'jp-VarInspector-title'; | ||
const PANEL_CLASS = 'jp-VarInspector'; | ||
const TABLE_CLASS = 'jp-VarInspector-table'; | ||
const TABLE_BODY_CLASS = 'jp-VarInspector-content'; | ||
const TABLE_ROW_CLASS = 'jp-VarInspector-table-row'; | ||
const TABLE_ROW_HIDDEN_CLASS = 'jp-VarInspector-table-row-hidden'; | ||
const TABLE_TYPE_CLASS = 'jp-VarInspector-type'; | ||
|
@@ -34,8 +60,8 @@ export class VariableInspectorPanel | |
implements IVariableInspector | ||
{ | ||
private _source: IVariableInspector.IInspectable | null = null; | ||
private _table: WebDataGrid; | ||
private _filteredTable: HTMLDivElement; | ||
private _table: HTMLTableElement; | ||
private _title: HTMLElement; | ||
private _filtered: { type: Array<string>; name: Array<string> }; | ||
|
||
|
@@ -58,13 +84,13 @@ export class VariableInspectorPanel | |
protected intializeFilteredTable() { | ||
const filterType = this._filteredTable.querySelector( | ||
'.' + FILTER_TYPE_CLASS | ||
) as HTMLSelectElement; | ||
) as Select; | ||
const filterInput = this._filteredTable.querySelector( | ||
'.' + FILTER_INPUT_CLASS | ||
) as HTMLInputElement; | ||
) as TextField; | ||
const filterButton = this._filteredTable.querySelector( | ||
'.' + FILTER_BUTTON_CLASS | ||
) as HTMLButtonElement; | ||
) as Button; | ||
filterButton.addEventListener('click', () => { | ||
this.onFilterChange( | ||
filterType.value as FILTER_TYPES, | ||
|
@@ -137,14 +163,14 @@ export class VariableInspectorPanel | |
protected addFilteredOutRows() { | ||
const rows = this._table.querySelectorAll( | ||
'.' + TABLE_ROW_HIDDEN_CLASS | ||
) as NodeListOf<HTMLTableRowElement>; | ||
) as NodeListOf<DataGridRow>; | ||
for (let i = 0; i < rows.length; i++) { | ||
const rowName = rows[i].querySelector( | ||
'.' + TABLE_NAME_CLASS | ||
) as HTMLTableCellElement; | ||
) as DataGridCell; | ||
const rowType = rows[i].querySelector( | ||
'.' + TABLE_TYPE_CLASS | ||
) as HTMLTableCellElement; | ||
) as DataGridCell; | ||
if ( | ||
!this.stringInFilter(rowName.innerHTML, 'name') && | ||
!this._filtered['type'].includes(rowType.innerHTML) | ||
|
@@ -161,14 +187,14 @@ export class VariableInspectorPanel | |
protected filterOutTable() { | ||
const rows = this._table.querySelectorAll( | ||
'.' + TABLE_ROW_CLASS | ||
) as NodeListOf<HTMLTableRowElement>; | ||
) as NodeListOf<DataGridRow>; | ||
for (let i = 0; i < rows.length; i++) { | ||
const rowName = rows[i].querySelector( | ||
'.' + TABLE_NAME_CLASS | ||
) as HTMLTableCellElement; | ||
) as DataGridCell; | ||
const rowType = rows[i].querySelector( | ||
'.' + TABLE_TYPE_CLASS | ||
) as HTMLTableCellElement; | ||
) as DataGridCell; | ||
if ( | ||
this.stringInFilter(rowName.innerHTML, 'name') || | ||
this._filtered['type'].includes(rowType.innerHTML) | ||
|
@@ -178,6 +204,24 @@ export class VariableInspectorPanel | |
} | ||
} | ||
|
||
/* | ||
Goes through each row and if it finds a variable with name 'name', then it deletes it | ||
*/ | ||
protected removeRow(name: string) { | ||
const rows = this._table.querySelectorAll( | ||
'.' + TABLE_ROW_CLASS | ||
) as NodeListOf<DataGridRow>; | ||
for (let i = 0; i < rows.length; i++) { | ||
const cell = rows[i].querySelector( | ||
'.' + TABLE_NAME_CLASS | ||
) as DataGridCell; | ||
if (cell.innerHTML === name) { | ||
rows[i].remove(); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
get source(): IVariableInspector.IInspectable | null { | ||
return this._source; | ||
} | ||
|
@@ -230,18 +274,28 @@ export class VariableInspectorPanel | |
" Inspecting '" + title.kernelName + "' " + title.contextName; | ||
} | ||
|
||
this._table.innerHTML = ''; | ||
const headerRow = document.createElement('jp-data-grid-row') as DataGridRow; | ||
headerRow.className = 'sticky-header'; | ||
const columns = [' ', ' ', 'NAME', 'TYPE', 'SIZE', 'SHAPE', 'CONTENT']; | ||
for (let i = 0; i < columns.length; i++) { | ||
const headerCell = document.createElement( | ||
'jp-data-grid-cell' | ||
) as DataGridCell; | ||
headerCell.className = 'column-header'; | ||
headerCell.textContent = columns[i]; | ||
headerCell.gridColumn = (i + 1).toString(); | ||
headerRow.appendChild(headerCell); | ||
} | ||
this._table.appendChild(headerRow); | ||
|
||
//Render new variable state | ||
let row: HTMLTableRowElement; | ||
this._table.deleteTFoot(); | ||
this._table.createTFoot(); | ||
this._table.tFoot!.className = TABLE_BODY_CLASS; | ||
for (let index = 0; index < args.length; index++) { | ||
const item = args[index]; | ||
|
||
const name = item.varName; | ||
const varType = item.varType; | ||
|
||
row = this._table.tFoot!.insertRow(); | ||
const row = document.createElement('jp-data-grid-row') as DataGridRow; | ||
row.className = TABLE_ROW_CLASS; | ||
if (this._filtered['type'].includes(varType)) { | ||
row.className = TABLE_ROW_HIDDEN_CLASS; | ||
|
@@ -250,48 +304,67 @@ export class VariableInspectorPanel | |
} | ||
|
||
// Add delete icon and onclick event | ||
let cell = row.insertCell(0); | ||
let cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
cell.title = 'Delete Variable'; | ||
cell.className = 'jp-VarInspector-deleteButton'; | ||
cell.gridColumn = '1'; | ||
const closeButton = document.createElement('jp-button') as Button; | ||
closeButton.appearance = 'stealth'; | ||
const ico = closeIcon.element(); | ||
ico.className = 'icon-button'; | ||
ico.onclick = (ev: MouseEvent): any => { | ||
this.source?.performDelete(name); | ||
this.removeRow(name); | ||
}; | ||
cell.append(ico); | ||
closeButton.append(ico); | ||
cell.append(closeButton); | ||
row.appendChild(cell); | ||
|
||
// Add onclick event for inspection | ||
cell = row.insertCell(1); | ||
cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
if (item.isMatrix) { | ||
cell.title = 'View Contents'; | ||
cell.className = 'jp-VarInspector-inspectButton'; | ||
const searchButton = document.createElement('jp-button') as Button; | ||
searchButton.appearance = 'stealth'; | ||
const ico = searchIcon.element(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind using a |
||
ico.className = 'icon-button'; | ||
ico.onclick = (ev: MouseEvent): any => { | ||
console.log('Click on ' + name); | ||
this._source | ||
?.performMatrixInspection(name) | ||
?.performMatrixInspection(item.varName) | ||
.then((model: DataModel) => { | ||
this._showMatrix(model, name, varType); | ||
this._showMatrix(model, item.varName, item.varType); | ||
}); | ||
}; | ||
cell.append(ico); | ||
searchButton.append(ico); | ||
cell.append(searchButton); | ||
} else { | ||
cell.innerHTML = ''; | ||
} | ||
cell.gridColumn = '2'; | ||
row.appendChild(cell); | ||
|
||
cell = row.insertCell(2); | ||
cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
cell.className = TABLE_NAME_CLASS; | ||
cell.innerHTML = name; | ||
cell.gridColumn = '3'; | ||
row.appendChild(cell); | ||
|
||
// Add remaining cells | ||
cell = row.insertCell(3); | ||
cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
cell.innerHTML = varType; | ||
cell.className = TABLE_TYPE_CLASS; | ||
cell = row.insertCell(4); | ||
cell.gridColumn = '4'; | ||
row.appendChild(cell); | ||
cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
cell.innerHTML = item.varSize; | ||
cell = row.insertCell(5); | ||
cell.gridColumn = '5'; | ||
row.appendChild(cell); | ||
cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
cell.innerHTML = item.varShape; | ||
cell = row.insertCell(6); | ||
cell.gridColumn = '6'; | ||
row.appendChild(cell); | ||
|
||
cell = document.createElement('jp-data-grid-cell') as DataGridCell; | ||
const rendermime = this._source?.rendermime; | ||
if (item.isWidget && rendermime) { | ||
const model = new OutputAreaModel({ trusted: true }); | ||
|
@@ -304,6 +377,9 @@ export class VariableInspectorPanel | |
'</br>' | ||
); | ||
} | ||
cell.gridColumn = '7'; | ||
row.appendChild(cell); | ||
this._table.appendChild(row); | ||
} | ||
} | ||
|
||
|
@@ -356,25 +432,10 @@ namespace Private { | |
); | ||
} | ||
|
||
export function createTable(): HTMLTableElement { | ||
const table = document.createElement('table'); | ||
table.createTHead(); | ||
const hrow = table.tHead!.insertRow(0) as HTMLTableRowElement; | ||
|
||
const cell1 = hrow.insertCell(0); | ||
cell1.innerHTML = ''; | ||
const cell2 = hrow.insertCell(1); | ||
cell2.innerHTML = ''; | ||
const cell3 = hrow.insertCell(2); | ||
cell3.innerHTML = 'Name'; | ||
const cell4 = hrow.insertCell(3); | ||
cell4.innerHTML = 'Type'; | ||
const cell5 = hrow.insertCell(4); | ||
cell5.innerHTML = 'Size'; | ||
const cell6 = hrow.insertCell(5); | ||
cell6.innerHTML = 'Shape'; | ||
const cell7 = hrow.insertCell(6); | ||
cell7.innerHTML = 'Content'; | ||
export function createTable(): WebDataGrid { | ||
const table = document.createElement('jp-data-grid') as WebDataGrid; | ||
table.generateHeader = 'sticky'; | ||
table.gridTemplateColumns = '1fr 1fr 6fr 4fr 4fr 5fr 16fr'; | ||
return table; | ||
} | ||
|
||
|
@@ -387,27 +448,27 @@ namespace Private { | |
export function createFilterTable(): HTMLDivElement { | ||
const container = document.createElement('div'); | ||
container.className = 'filter-container'; | ||
const filterType = document.createElement('select'); | ||
const filterType = document.createElement('jp-select') as Select; | ||
filterType.className = FILTER_TYPE_CLASS; | ||
filterType.selectedIndex = 0; | ||
const varTypeOption = document.createElement('option'); | ||
const varTypeOption = document.createElement('jp-option') as Option; | ||
varTypeOption.value = 'type'; | ||
varTypeOption.innerHTML = 'Type'; | ||
const nameOption = document.createElement('option'); | ||
const nameOption = document.createElement('jp-option') as Option; | ||
nameOption.value = 'name'; | ||
nameOption.innerHTML = 'Name'; | ||
filterType.appendChild(varTypeOption); | ||
filterType.appendChild(nameOption); | ||
const searchContainer = document.createElement('div'); | ||
searchContainer.className = 'jp-InputGroup filter-search-container'; | ||
const input = document.createElement('input'); | ||
const input = document.createElement('jp-text-field') as TextField; | ||
input.setAttribute('type', 'text'); | ||
input.setAttribute('placeholder', 'Filter out variable'); | ||
input.className = FILTER_INPUT_CLASS; | ||
const filterButton = document.createElement('button'); | ||
const buttonText = document.createTextNode('Filter'); | ||
filterButton.appendChild(buttonText); | ||
const filterButton = document.createElement('jp-button') as Button; | ||
filterButton.textContent = 'Filter'; | ||
filterButton.className = FILTER_BUTTON_CLASS; | ||
filterButton.appearance = 'accent'; | ||
const list = document.createElement('ul'); | ||
list.className = FILTER_LIST_CLASS; | ||
|
||
|
@@ -423,18 +484,22 @@ namespace Private { | |
export function createFilteredButton( | ||
filterName: string, | ||
filterType: FILTER_TYPES | ||
): HTMLButtonElement { | ||
const filteredButton = document.createElement('button'); | ||
): Button { | ||
const filteredButton = document.createElement('jp-button') as Button; | ||
filteredButton.value = filterType; | ||
filteredButton.title = filterType; | ||
filteredButton.className = FILTERED_BUTTON_CLASS; | ||
const filterButtonContent = document.createElement('div'); | ||
filterButtonContent.className = 'filter-button-content'; | ||
const buttonText = document.createElement('div'); | ||
buttonText.className = 'filtered-variable-button-text'; | ||
buttonText.innerHTML = filterName; | ||
const icon = closeIcon.element({ | ||
container: filteredButton | ||
container: filterButtonContent | ||
}); | ||
filteredButton.appendChild(buttonText); | ||
filteredButton.appendChild(icon); | ||
filterButtonContent.appendChild(buttonText); | ||
filterButtonContent.appendChild(icon); | ||
filteredButton.appendChild(filterButtonContent); | ||
filteredButton.className = FILTERED_BUTTON_CLASS; | ||
return filteredButton; | ||
} | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you wrap this icon in a
jp-button
with appearance stealth?