This commit is contained in:
parent
2a19eb9901
commit
648d56010d
|
|
@ -789,8 +789,6 @@ class DeviceInterfaceTable(InterfaceTable):
|
|||
'data-virtual': lambda record: "true" if record.is_virtual else "false",
|
||||
'data-mark-connected': lambda record: "true" if record.mark_connected else "false",
|
||||
'data-cable-status': lambda record: record.cable.status if record.cable else "",
|
||||
'data-type': lambda record: record.type,
|
||||
'data-connected': lambda record: "connected" if record.mark_connected or record.cable else "disconnected"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -8,7 +8,6 @@ import { initMessages } from './messages';
|
|||
import { initClipboard } from './clipboard';
|
||||
import { initDateSelector } from './dateSelector';
|
||||
import { initTableConfig } from './tableConfig';
|
||||
import { initInterfaceTable } from './tables';
|
||||
import { initSideNav } from './sidenav';
|
||||
import { initDashboard } from './dashboard';
|
||||
import { initRackElevation } from './racks';
|
||||
|
|
@ -28,7 +27,6 @@ function initDocument(): void {
|
|||
initButtons,
|
||||
initClipboard,
|
||||
initTableConfig,
|
||||
initInterfaceTable,
|
||||
initSideNav,
|
||||
initDashboard,
|
||||
initRackElevation,
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export * from './interfaceTable';
|
||||
|
|
@ -1,251 +0,0 @@
|
|||
import { getElements, replaceAll, findFirstAdjacent } from '../util';
|
||||
|
||||
type ShowHide = 'show' | 'hide';
|
||||
|
||||
function isShowHide(value: unknown): value is ShowHide {
|
||||
return typeof value === 'string' && ['show', 'hide'].includes(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* When this error is thrown, it's an indication that we don't need to manage this table, because
|
||||
* it doesn't contain the required elements.
|
||||
*/
|
||||
class TableStateError extends Error {
|
||||
table: HTMLTableElement;
|
||||
constructor(message: string, table: HTMLTableElement) {
|
||||
super(message);
|
||||
this.table = table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the display text of a button element as well as the visibility of its corresponding rows.
|
||||
*/
|
||||
class ButtonState {
|
||||
/**
|
||||
* Underlying Button DOM Element
|
||||
*/
|
||||
public button: HTMLButtonElement;
|
||||
|
||||
/**
|
||||
* Table rows provided in constructor
|
||||
*/
|
||||
private rows: NodeListOf<HTMLTableRowElement>;
|
||||
|
||||
constructor(button: HTMLButtonElement, rows: NodeListOf<HTMLTableRowElement>) {
|
||||
this.button = button;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove visibility of button state rows.
|
||||
*/
|
||||
private hideRows(): void {
|
||||
for (const row of this.rows) {
|
||||
row.classList.add('d-none');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the DOM element's `data-state` attribute.
|
||||
*/
|
||||
public set buttonState(state: Nullable<ShowHide>) {
|
||||
if (isShowHide(state)) {
|
||||
this.button.setAttribute('data-state', state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DOM element's `data-state` attribute.
|
||||
*/
|
||||
public get buttonState(): Nullable<ShowHide> {
|
||||
const state = this.button.getAttribute('data-state');
|
||||
if (isShowHide(state)) {
|
||||
return state;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the DOM element's display text to reflect the action opposite the current state. For
|
||||
* example, if the current state is to hide enabled interfaces, the DOM text should say
|
||||
* "Show Enabled Interfaces".
|
||||
*/
|
||||
private toggleButton(): void {
|
||||
if (this.buttonState === 'show') {
|
||||
this.button.innerText = replaceAll(this.button.innerText, 'Show', 'Hide');
|
||||
} else if (this.buttonState === 'hide') {
|
||||
this.button.innerText = replaceAll(this.button.innerHTML, 'Hide', 'Show');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the DOM element's `data-state` attribute.
|
||||
*/
|
||||
private toggleState(): void {
|
||||
if (this.buttonState === 'show') {
|
||||
this.buttonState = 'hide';
|
||||
} else if (this.buttonState === 'hide') {
|
||||
this.buttonState = 'show';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle all controlled elements.
|
||||
*/
|
||||
private toggle(): void {
|
||||
this.toggleState();
|
||||
this.toggleButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* When the button is clicked, toggle all controlled elements and hide rows based on
|
||||
* buttonstate.
|
||||
*/
|
||||
public handleClick(event: Event): void {
|
||||
const button = event.currentTarget as HTMLButtonElement;
|
||||
if (button.isEqualNode(this.button)) {
|
||||
this.toggle();
|
||||
}
|
||||
if (this.buttonState === 'hide') {
|
||||
this.hideRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the state of a table and its elements.
|
||||
*/
|
||||
class TableState {
|
||||
/**
|
||||
* Underlying DOM Table Element.
|
||||
*/
|
||||
|
||||
private table: HTMLTableElement;
|
||||
/**
|
||||
* Instance of ButtonState for the 'show/hide enabled rows' button.
|
||||
*/
|
||||
// @ts-expect-error null handling is performed in the constructor
|
||||
private enabledButton: ButtonState;
|
||||
|
||||
/**
|
||||
* Instance of ButtonState for the 'show/hide disabled rows' button.
|
||||
*/
|
||||
// @ts-expect-error null handling is performed in the constructor
|
||||
private disabledButton: ButtonState;
|
||||
|
||||
/**
|
||||
* Instance of ButtonState for the 'show/hide virtual rows' button.
|
||||
*/
|
||||
// @ts-expect-error null handling is performed in the constructor
|
||||
private virtualButton: ButtonState;
|
||||
|
||||
/**
|
||||
* Instance of ButtonState for the 'show/hide virtual rows' button.
|
||||
*/
|
||||
// @ts-expect-error null handling is performed in the constructor
|
||||
private disconnectedButton: ButtonState;
|
||||
|
||||
/**
|
||||
* All table rows in table
|
||||
*/
|
||||
private rows: NodeListOf<HTMLTableRowElement>;
|
||||
|
||||
constructor(table: HTMLTableElement) {
|
||||
this.table = table;
|
||||
this.rows = this.table.querySelectorAll('tr');
|
||||
try {
|
||||
const toggleEnabledButton = findFirstAdjacent<HTMLButtonElement>(
|
||||
this.table,
|
||||
'button.toggle-enabled',
|
||||
);
|
||||
const toggleDisabledButton = findFirstAdjacent<HTMLButtonElement>(
|
||||
this.table,
|
||||
'button.toggle-disabled',
|
||||
);
|
||||
const toggleVirtualButton = findFirstAdjacent<HTMLButtonElement>(
|
||||
this.table,
|
||||
'button.toggle-virtual',
|
||||
);
|
||||
const toggleDisconnectedButton = findFirstAdjacent<HTMLButtonElement>(
|
||||
this.table,
|
||||
'button.toggle-disconnected',
|
||||
);
|
||||
|
||||
if (toggleEnabledButton === null) {
|
||||
throw new TableStateError("Table is missing a 'toggle-enabled' button.", table);
|
||||
}
|
||||
|
||||
if (toggleDisabledButton === null) {
|
||||
throw new TableStateError("Table is missing a 'toggle-disabled' button.", table);
|
||||
}
|
||||
|
||||
if (toggleVirtualButton === null) {
|
||||
throw new TableStateError("Table is missing a 'toggle-virtual' button.", table);
|
||||
}
|
||||
|
||||
if (toggleDisconnectedButton === null) {
|
||||
throw new TableStateError("Table is missing a 'toggle-disconnected' button.", table);
|
||||
}
|
||||
|
||||
// Attach event listeners to the buttons elements.
|
||||
toggleEnabledButton.addEventListener('click', event => this.handleClick(event, this));
|
||||
toggleDisabledButton.addEventListener('click', event => this.handleClick(event, this));
|
||||
toggleVirtualButton.addEventListener('click', event => this.handleClick(event, this));
|
||||
toggleDisconnectedButton.addEventListener('click', event => this.handleClick(event, this));
|
||||
|
||||
// Instantiate ButtonState for each button for state management.
|
||||
this.enabledButton = new ButtonState(
|
||||
toggleEnabledButton,
|
||||
table.querySelectorAll<HTMLTableRowElement>('tr[data-enabled="enabled"]'),
|
||||
);
|
||||
this.disabledButton = new ButtonState(
|
||||
toggleDisabledButton,
|
||||
table.querySelectorAll<HTMLTableRowElement>('tr[data-enabled="disabled"]'),
|
||||
);
|
||||
this.virtualButton = new ButtonState(
|
||||
toggleVirtualButton,
|
||||
table.querySelectorAll<HTMLTableRowElement>('tr[data-type="virtual"]'),
|
||||
);
|
||||
this.disconnectedButton = new ButtonState(
|
||||
toggleDisconnectedButton,
|
||||
table.querySelectorAll<HTMLTableRowElement>('tr[data-connected="disconnected"]'),
|
||||
);
|
||||
} catch (err) {
|
||||
if (err instanceof TableStateError) {
|
||||
// This class is useless for tables that don't have toggle buttons.
|
||||
console.debug('Table does not contain enable/disable toggle buttons');
|
||||
return;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When toggle buttons are clicked, reapply visability all rows and
|
||||
* pass the event to all button handlers
|
||||
*
|
||||
* @param event onClick event for toggle buttons.
|
||||
* @param instance Instance of TableState (`this` cannot be used since that's context-specific).
|
||||
*/
|
||||
public handleClick(event: Event, instance: TableState): void {
|
||||
for (const row of this.rows) {
|
||||
row.classList.remove('d-none');
|
||||
}
|
||||
|
||||
instance.enabledButton.handleClick(event);
|
||||
instance.disabledButton.handleClick(event);
|
||||
instance.virtualButton.handleClick(event);
|
||||
instance.disconnectedButton.handleClick(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize table states.
|
||||
*/
|
||||
export function initInterfaceTable(): void {
|
||||
for (const element of getElements<HTMLTableElement>('table')) {
|
||||
new TableState(element);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,35 @@
|
|||
|
||||
{% block extra_table_controls %}
|
||||
<button class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="mdi mdi-eye"></i>
|
||||
<i class="mdi mdi-eye" aria-hidden="true"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<button type="button" class="dropdown-item toggle-enabled" data-state="show">{% trans "Hide Enabled" %}</button>
|
||||
<button type="button" class="dropdown-item toggle-disabled" data-state="show">{% trans "Hide Disabled" %}</button>
|
||||
<button type="button" class="dropdown-item toggle-virtual" data-state="show">{% trans "Hide Virtual" %}</button>
|
||||
<button type="button" class="dropdown-item toggle-disconnected" data-state="show">{% trans "Hide Disconnected" %}</button>
|
||||
{# enabled filter: True = show only enabled (hide disabled), False = show only disabled (hide enabled) #}
|
||||
<li>
|
||||
<a class="dropdown-item{% if request.GET.enabled == 'True' %} active{% endif %}"
|
||||
href="{{ request.path }}{% if request.GET.enabled == 'True' %}{% querystring enabled=None %}{% else %}{% querystring enabled='True' %}{% endif %}">
|
||||
{% if request.GET.enabled == 'True' %}<i class="mdi mdi-check" aria-hidden="true"></i> {% endif %}{% trans "Hide Disabled" %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item{% if request.GET.enabled == 'False' %} active{% endif %}"
|
||||
href="{{ request.path }}{% if request.GET.enabled == 'False' %}{% querystring enabled=None %}{% else %}{% querystring enabled='False' %}{% endif %}">
|
||||
{% if request.GET.enabled == 'False' %}<i class="mdi mdi-check" aria-hidden="true"></i> {% endif %}{% trans "Hide Enabled" %}
|
||||
</a>
|
||||
</li>
|
||||
{# kind filter: physical = show only physical (hide virtual/wireless) #}
|
||||
<li>
|
||||
<a class="dropdown-item{% if request.GET.kind == 'physical' %} active{% endif %}"
|
||||
href="{{ request.path }}{% if request.GET.kind == 'physical' %}{% querystring kind=None %}{% else %}{% querystring kind='physical' %}{% endif %}">
|
||||
{% if request.GET.kind == 'physical' %}<i class="mdi mdi-check" aria-hidden="true"></i> {% endif %}{% trans "Hide Virtual" %}
|
||||
</a>
|
||||
</li>
|
||||
{# connected filter: True = show only connected (hide disconnected) #}
|
||||
<li>
|
||||
<a class="dropdown-item{% if request.GET.connected == 'True' %} active{% endif %}"
|
||||
href="{{ request.path }}{% if request.GET.connected == 'True' %}{% querystring connected=None %}{% else %}{% querystring connected='True' %}{% endif %}">
|
||||
{% if request.GET.connected == 'True' %}<i class="mdi mdi-check" aria-hidden="true"></i> {% endif %}{% trans "Hide Disconnected" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endblock extra_table_controls %}
|
||||
|
|
|
|||
Loading…
Reference in New Issue