Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add option to filter out variables #290

Merged
merged 9 commits into from
Nov 29, 2023
188 changes: 187 additions & 1 deletion src/variableinspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ 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';
const TABLE_NAME_CLASS = 'jp-VarInspector-varName';
const FILTER_TYPE_CLASS = 'filter-type';
const FILTER_INPUT_CLASS = 'filter-input';
const FILTER_BUTTON_CLASS = 'filter-button';
const FILTER_LIST_CLASS = 'filter-list';
const FILTERED_BUTTON_CLASS = 'filtered-variable-button';

type FILTER_TYPES = 'type' | 'name';

/**
* A panel that renders the variables
Expand All @@ -21,8 +32,10 @@ export class VariableInspectorPanel
implements IVariableInspector
{
private _source: IVariableInspector.IInspectable | null = null;
private _filteredTable: HTMLDivElement;
private _table: HTMLTableElement;
private _title: HTMLElement;
private _filtered: { type: Array<string>; name: Array<string> };

constructor() {
super();
Expand All @@ -31,8 +44,121 @@ export class VariableInspectorPanel
this._title.className = TITLE_CLASS;
this._table = Private.createTable();
this._table.className = TABLE_CLASS;
this._filteredTable = Private.createFilterTable();
this.node.appendChild(this._title as HTMLElement);
this.node.appendChild(this._filteredTable as HTMLElement);
this.node.appendChild(this._table as HTMLElement);
this._filtered = { type: [], name: [] };
this.intializeFilteredTable();
}

protected intializeFilteredTable() {
const filterType = this._filteredTable.querySelector(
'.' + FILTER_TYPE_CLASS
) as HTMLSelectElement;
const filterInput = this._filteredTable.querySelector(
'.' + FILTER_INPUT_CLASS
) as HTMLInputElement;
const filterButton = this._filteredTable.querySelector(
'.' + FILTER_BUTTON_CLASS
) as HTMLButtonElement;
filterButton.addEventListener('click', () => {
this.onFilterChange(
filterType.value as FILTER_TYPES,
filterInput.value,
true
);
});
}

// Checks if string is in the filtered array
protected stringInFilter(string: string, filterType: FILTER_TYPES) {
// console.log(this._filtered[filterType]);
for (let i = 0; i < this._filtered[filterType].length; i++) {
if (string.match(new RegExp(this._filtered[filterType][i]))) {
return true;
}
}
return false;
}

protected onFilterChange(
filterType: FILTER_TYPES,
varName: string,
isAdding: boolean
) {
if (varName === '') {
return;
}
if (isAdding) {
if (this._filtered[filterType].includes(varName)) {
return;
}
this._filtered[filterType].push(varName);
const filterList = this._filteredTable.querySelector(
'.' + FILTER_LIST_CLASS
) as HTMLUListElement;
const newFilteredButton = Private.createFilteredButton(
varName,
filterType
);
newFilteredButton.addEventListener('click', () => {
const filterText = newFilteredButton.querySelector(
'.filtered-variable-button-text'
) as HTMLDivElement;
this.onFilterChange(filterType, filterText.innerHTML, false);
this.addFilteredOutRows();
newFilteredButton.remove();
});
filterList.appendChild(newFilteredButton);
this.filterOutTable();
} else {
console.log(this._filtered[filterType]);
console.log(varName);
this._filtered[filterType] = this._filtered[filterType].filter(
filter => filter !== varName
);
}
}

protected addFilteredOutRows() {
const rows = this._table.querySelectorAll(
'.' + TABLE_ROW_HIDDEN_CLASS
) as NodeListOf<HTMLTableRowElement>;
for (let i = 0; i < rows.length; i++) {
const rowName = rows[i].querySelector(
'.' + TABLE_NAME_CLASS
) as HTMLTableCellElement;
const rowType = rows[i].querySelector(
'.' + TABLE_TYPE_CLASS
) as HTMLTableCellElement;
if (
!this.stringInFilter(rowName.innerHTML, 'name') &&
!this._filtered['type'].includes(rowType.innerHTML)
) {
rows[i].className = TABLE_ROW_CLASS;
}
}
}

protected filterOutTable() {
const rows = this._table.querySelectorAll(
'.' + TABLE_ROW_CLASS
) as NodeListOf<HTMLTableRowElement>;
for (let i = 0; i < rows.length; i++) {
const rowName = rows[i].querySelector(
'.' + TABLE_NAME_CLASS
) as HTMLTableCellElement;
const rowType = rows[i].querySelector(
'.' + TABLE_TYPE_CLASS
) as HTMLTableCellElement;
if (
this.stringInFilter(rowName.innerHTML, 'name') ||
this._filtered['type'].includes(rowType.innerHTML)
) {
rows[i].className = TABLE_ROW_HIDDEN_CLASS;
}
}
}

get source(): IVariableInspector.IInspectable | null {
Expand Down Expand Up @@ -99,6 +225,12 @@ export class VariableInspectorPanel
const varType = item.varType;

row = this._table.tFoot!.insertRow();
row.className = TABLE_ROW_CLASS;
if (this._filtered['type'].includes(varType)) {
row.className = TABLE_ROW_HIDDEN_CLASS;
} else if (this.stringInFilter(name, 'name')) {
row.className = TABLE_ROW_HIDDEN_CLASS;
}

// Add delete icon and onclick event
let cell = row.insertCell(0);
Expand Down Expand Up @@ -130,12 +262,13 @@ export class VariableInspectorPanel
}

cell = row.insertCell(2);
cell.className = 'jp-VarInspector-varName';
cell.className = TABLE_NAME_CLASS;
cell.innerHTML = name;

// Add remaining cells
cell = row.insertCell(3);
cell.innerHTML = varType;
cell.className = TABLE_TYPE_CLASS;
cell = row.insertCell(4);
cell.innerHTML = item.varSize;
cell = row.insertCell(5);
Expand Down Expand Up @@ -233,4 +366,57 @@ namespace Private {
title.innerHTML = header;
return title;
}

export function createFilterTable(): HTMLDivElement {
const container = document.createElement('div');
container.className = 'filter-container';
const filterType = document.createElement('select');
filterType.className = FILTER_TYPE_CLASS;
const varTypeOption = document.createElement('option');
varTypeOption.value = 'type';
varTypeOption.innerHTML = 'Type';
const nameOption = document.createElement('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');
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);
filterButton.className = FILTER_BUTTON_CLASS;
const list = document.createElement('ul');
list.className = FILTER_LIST_CLASS;

searchContainer.appendChild(filterType);
searchContainer.appendChild(input);
searchContainer.appendChild(filterButton);
container.appendChild(searchContainer);
container.appendChild(list);
return container;
}

export function createFilteredButton(
filterName: string,
filterType: FILTER_TYPES
): HTMLButtonElement {
const filteredButton = document.createElement('button');
filteredButton.value = filterType;
filteredButton.title = filterType;
const buttonText = document.createElement('div');
buttonText.className = 'filtered-variable-button-text';
buttonText.innerHTML = filterName;
const icon = closeIcon.element({
container: filteredButton
});
filteredButton.appendChild(buttonText);
filteredButton.appendChild(icon);
filteredButton.className = FILTERED_BUTTON_CLASS;
return filteredButton;
}
}
63 changes: 63 additions & 0 deletions style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,69 @@
padding-left: 10px;
}

.filter-container {
display: flex;
flex-direction: column;
}

.filter-search-container {
display: flex;
padding: 0 1rem;
}

.filter-type {
background-color: var(--jp-ui-font-color2);
color: var(--jp-ui-font-color1);
box-shadow: inset 0 0 0 var(--jp-border-width) var(--jp-input-border-color);
border: none;
padding: 0 0.5rem;
text-align: center;
}

.filter-input {
width: 20rem !important;
margin-left: 1rem;
}

.filter-button {
background-color: var(--jp-ui-font-color2);
color: var(--jp-ui-font-color1);
box-shadow: inset 0 0 0 var(--jp-border-width) var(--jp-input-border-color);
border: none;
padding: 0 0.5rem;
}

.filtered-variable-button {
background-color: transparent;
box-shadow: inset 0 0 0 var(--jp-border-width) var(--jp-input-border-color);
border: none;
padding: 0.25rem 0.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
}

.filtered-variable-button-text {
color: var(--jp-ui-font-color1);
background-color: transparent;
}

.type-button {
color: var(--jp-ui-font-color0);
}

.name-button {
color: var(--jp-ui-font-color1);
}

.filter-list {
display: flex;
}

.jp-VarInspector-table-row-hidden {
display: none;
}

.jp-VarInspector-deleteButton {
text-align: center;
width: 1em;
Expand Down