Workers table: Add multi-select and support actions for multiple items (#104395)
Add the following features: - `Ctrl + Click` or `Cmd + Click` to toggle selection of additional workers - `Shift + Click` to select a range of additional workers - Ability to perform `Shutdown`, `Send To Sleep`, and `Wake Up` actions on multiple workers concurrently - Notifications on how many workers successfully/failed to have an action performed Reviewed-on: https://projects.blender.org/studio/flamenco/pulls/104395 Reviewed-by: Sybren A. Stüvel <sybren@blender.org>
This commit is contained in:
parent
29e0eefdd1
commit
bd2ebac519
@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<select v-model="selectedAction">
|
<select v-model="selectedAction">
|
||||||
<option value="" selected>
|
<option value="" selected>
|
||||||
<template v-if="!hasActiveWorker">Select a Worker</template>
|
<template v-if="!workers.selectedWorkers.length">Select a Worker</template>
|
||||||
<template v-else>Choose an action...</template>
|
<template v-else>Choose an action...</template>
|
||||||
</option>
|
</option>
|
||||||
<template v-for="(action, key) in WORKER_ACTIONS">
|
<template v-for="(action, key) in WORKER_ACTIONS">
|
||||||
<option :value="key" v-if="action.condition()">{{ action.label }}</option>
|
<option :key="action.label" :value="key" v-if="action.condition()">
|
||||||
|
{{ action.label }}
|
||||||
|
</option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
<button :disabled="!canPerformAction" class="btn" @click.prevent="performWorkerAction">
|
<button :disabled="!canPerformAction" class="btn" @click.prevent="performWorkerAction">
|
||||||
@ -84,26 +86,30 @@ const WORKER_ACTIONS = Object.freeze({
|
|||||||
|
|
||||||
const selectedAction = ref('');
|
const selectedAction = ref('');
|
||||||
const workers = useWorkers();
|
const workers = useWorkers();
|
||||||
const hasActiveWorker = computed(() => !!workers.activeWorkerID);
|
const canPerformAction = computed(() => workers.selectedWorkers.length && !!selectedAction.value);
|
||||||
const canPerformAction = computed(() => hasActiveWorker && !!selectedAction.value);
|
|
||||||
const notifs = useNotifs();
|
const notifs = useNotifs();
|
||||||
|
|
||||||
function performWorkerAction() {
|
function performWorkerAction() {
|
||||||
const workerID = workers.activeWorkerID;
|
if (!workers.selectedWorkers.length) {
|
||||||
if (!workerID) {
|
notifs.add('Select at least one Worker before applying an action.');
|
||||||
notifs.add('Select a Worker before applying an action.');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const api = new WorkerMgtApi(getAPIClient());
|
const api = new WorkerMgtApi(getAPIClient()); // Init the api
|
||||||
const action = WORKER_ACTIONS[selectedAction.value];
|
const action = WORKER_ACTIONS[selectedAction.value];
|
||||||
const statuschange = new WorkerStatusChangeRequest(action.target_status, action.lazy);
|
const statuschange = new WorkerStatusChangeRequest(action.target_status, action.lazy);
|
||||||
console.log('Requesting worker status change', statuschange);
|
|
||||||
api
|
const promises = workers.selectedWorkers.map((worker) =>
|
||||||
.requestWorkerStatusChange(workerID, statuschange)
|
api
|
||||||
.then((result) => notifs.add(`Worker status change to ${action.target_status} confirmed.`))
|
.requestWorkerStatusChange(worker.id, statuschange)
|
||||||
.catch((error) => {
|
.then(() =>
|
||||||
notifs.add(`Error requesting worker status change: ${error.body.message}`);
|
notifs.add(`Worker ${worker.name} status change to ${action.target_status} confirmed.`)
|
||||||
});
|
)
|
||||||
|
.catch((error) =>
|
||||||
|
notifs.add(`Error requesting worker ${worker.name} status change: ${error.body.message}`)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Promise.allSettled(promises);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -39,9 +39,11 @@ export default {
|
|||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
workers: useWorkers(),
|
workers: useWorkers(),
|
||||||
|
api: new WorkerMgtApi(getAPIClient()),
|
||||||
|
|
||||||
shownStatuses: [],
|
shownStatuses: [],
|
||||||
availableStatuses: [], // Will be filled after data is loaded from the backend.
|
availableStatuses: [], // Will be filled after data is loaded from the backend.
|
||||||
|
lastSelectedWorkerPosition: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -100,82 +102,210 @@ export default {
|
|||||||
this.$nextTick(this.recalcTableHeight);
|
this.$nextTick(this.recalcTableHeight);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
selectedIDs() {
|
|
||||||
return this.tabulator.getSelectedData().map((worker) => worker.id);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
onReconnected() {
|
/**
|
||||||
|
* @param {string} workerID worker ID to navigate to, can be empty string for "no active worker".
|
||||||
|
*/
|
||||||
|
_routeToWorker(workerID) {
|
||||||
|
const route = { name: 'workers', params: { workerID: workerID } };
|
||||||
|
this.$router.push(route);
|
||||||
|
},
|
||||||
|
async onReconnected() {
|
||||||
// If the connection to the backend was lost, we have likely missed some
|
// If the connection to the backend was lost, we have likely missed some
|
||||||
// updates. Just fetch the data and start from scratch.
|
// updates. Just re-initialize the data and start from scratch.
|
||||||
this.fetchAllWorkers();
|
await this.initAllWorkers();
|
||||||
|
await this.initActiveWorker();
|
||||||
},
|
},
|
||||||
sortData() {
|
sortData() {
|
||||||
const tab = this.tabulator;
|
const tab = this.tabulator;
|
||||||
tab.setSort(tab.getSorters()); // This triggers re-sorting.
|
tab.setSort(tab.getSorters()); // This triggers re-sorting.
|
||||||
},
|
},
|
||||||
_onTableBuilt() {
|
async _onTableBuilt() {
|
||||||
this.tabulator.setFilter(this._filterByStatus);
|
this.tabulator.setFilter(this._filterByStatus);
|
||||||
this.fetchAllWorkers();
|
await this.initAllWorkers();
|
||||||
|
await this.initActiveWorker();
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Initializes the active worker. Updates pinia stores and state accordingly.
|
||||||
|
*/
|
||||||
|
async initActiveWorker() {
|
||||||
|
// If there's no active Worker, reset the state and Pinia stores
|
||||||
|
if (!this.activeWorkerID) {
|
||||||
|
this.workers.clearActiveWorker();
|
||||||
|
this.workers.clearSelectedWorkers();
|
||||||
|
this.lastSelectedWorkerPosition = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const worker = await this.fetchWorker(this.activeWorkerID);
|
||||||
|
|
||||||
|
this.workers.setActiveWorker(worker);
|
||||||
|
this.workers.setSelectedWorkers([worker]);
|
||||||
|
|
||||||
|
const activeRow = this.tabulator.getRow(this.activeWorkerID);
|
||||||
|
// If the page is reloaded, re-initialize the last selected worker (or active worker)
|
||||||
|
// position, allowing the user to multi-select from that worker.
|
||||||
|
this.lastSelectedWorkerPosition = activeRow.getPosition();
|
||||||
|
// Make sure the active row on tabulator has the selected status toggled as well
|
||||||
|
this.tabulator.selectRow(activeRow);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Fetch a Worker based on ID
|
||||||
|
*/
|
||||||
|
fetchWorker(workerID) {
|
||||||
|
return this.api
|
||||||
|
.fetchWorker(workerID)
|
||||||
|
.then((worker) => worker)
|
||||||
|
.catch((err) => {
|
||||||
|
throw new Error(`Unable to fetch worker with ID ${workerID}:`, err);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Initializes all workers and sets the Tabulator data. Updates pinia stores and state accordingly.
|
||||||
|
*/
|
||||||
|
async initAllWorkers() {
|
||||||
|
try {
|
||||||
|
const workers = await this.fetchAllWorkers();
|
||||||
|
this.tabulator.setData(workers);
|
||||||
|
this._refreshAvailableStatuses();
|
||||||
|
this.recalcTableHeight();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Fetch all workers
|
||||||
|
*/
|
||||||
fetchAllWorkers() {
|
fetchAllWorkers() {
|
||||||
const api = new WorkerMgtApi(getAPIClient());
|
return this.api
|
||||||
api.fetchWorkers().then(this.onWorkersFetched, function (error) {
|
.fetchWorkers()
|
||||||
// TODO: error handling.
|
.then((data) => data.workers)
|
||||||
console.error(error);
|
.catch((e) => {
|
||||||
});
|
throw new Error('Unable to fetch all workers:', e);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onWorkersFetched(data) {
|
async processWorkerUpdate(workerUpdate) {
|
||||||
this.tabulator.setData(data.workers);
|
|
||||||
this._refreshAvailableStatuses();
|
|
||||||
this.recalcTableHeight();
|
|
||||||
},
|
|
||||||
processWorkerUpdate(workerUpdate) {
|
|
||||||
if (!this.tabulator.initialized) return;
|
if (!this.tabulator.initialized) return;
|
||||||
|
|
||||||
// Contrary to tabulator.getRow(), rowManager.findRow() doesn't log a
|
try {
|
||||||
// warning when the row cannot be found,
|
// Contrary to tabulator.getRow(), rowManager.findRow() doesn't log a
|
||||||
const existingRow = this.tabulator.rowManager.findRow(workerUpdate.id);
|
// warning when the row cannot be found,
|
||||||
|
const existingRow = this.tabulator.rowManager.findRow(workerUpdate.id);
|
||||||
|
|
||||||
let promise;
|
// Delete the row
|
||||||
// TODO: clean up the code below:
|
if (existingRow && workerUpdate.deleted_at) {
|
||||||
if (existingRow) {
|
// Prevents the issue where deleted rows persist on Tabulator's selectedData
|
||||||
if (workerUpdate.deleted_at) {
|
this.tabulator.deselectRow(workerUpdate.id);
|
||||||
// This is a deletion, not a regular update.
|
await existingRow.delete();
|
||||||
promise = existingRow.delete();
|
|
||||||
} else {
|
// If the deleted worker was active, route to /workers
|
||||||
// Tabbulator doesn't update ommitted fields, but if `status_change`
|
if (workerUpdate.id === this.activeWorkerID) {
|
||||||
|
this._routeToWorker('');
|
||||||
|
// Update Pinia Stores
|
||||||
|
this.workers.clearActiveWorker();
|
||||||
|
}
|
||||||
|
// Update Pinia Stores
|
||||||
|
this.workers.setSelectedWorkers(this.getSelectedWorkers());
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existingRow) {
|
||||||
|
// Prepare to update an existing row.
|
||||||
|
// Tabulator doesn't update ommitted fields, but if `status_change`
|
||||||
// is ommitted it means "no status change requested"; this should still
|
// is ommitted it means "no status change requested"; this should still
|
||||||
// force an update of the `status_change` field.
|
// force an update of the `status_change` field.
|
||||||
if (!workerUpdate.status_change) {
|
workerUpdate.status_change = workerUpdate.status_change || null;
|
||||||
workerUpdate.status_change = null;
|
|
||||||
}
|
// Update the existing row.
|
||||||
promise = this.tabulator.updateData([workerUpdate]);
|
|
||||||
// Tabulator doesn't know we're using 'status_change' in the 'status'
|
// Tabulator doesn't know we're using 'status_change' in the 'status'
|
||||||
// column, so it also won't know to redraw when that field changes.
|
// column, so it also won't know to redraw when that field changes.
|
||||||
promise.then(() => existingRow.reinitialize(true));
|
await this.tabulator.updateData([workerUpdate]);
|
||||||
|
existingRow.reinitialize(true);
|
||||||
|
} else {
|
||||||
|
await this.tabulator.addData([workerUpdate]); // Add a new row.
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
promise = this.tabulator.addData([workerUpdate]);
|
this.sortData();
|
||||||
|
await this.tabulator.redraw();
|
||||||
|
this._refreshAvailableStatuses(); // Resize columns based on new data.
|
||||||
|
|
||||||
|
// Update Pinia stores
|
||||||
|
this.workers.setSelectedWorkers(this.getSelectedWorkers());
|
||||||
|
if (workerUpdate.id === this.activeWorkerID) {
|
||||||
|
const worker = await this.fetchWorker(this.activeWorkerID);
|
||||||
|
this.workers.setActiveWorker(worker);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this should also resize the columns, as the status column can
|
||||||
|
// change sizes considerably.
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
}
|
}
|
||||||
promise
|
|
||||||
.then(this.sortData)
|
|
||||||
.then(() => {
|
|
||||||
this.tabulator.redraw();
|
|
||||||
}) // Resize columns based on new data.
|
|
||||||
.then(this._refreshAvailableStatuses);
|
|
||||||
|
|
||||||
// TODO: this should also resize the columns, as the status column can
|
|
||||||
// change sizes considerably.
|
|
||||||
},
|
},
|
||||||
|
handleMultiSelect(event, row, tabulator) {
|
||||||
|
const position = row.getPosition();
|
||||||
|
|
||||||
onRowClick(event, row) {
|
// Manage the click event and Tabulator row selection
|
||||||
|
if (event.shiftKey && this.lastSelectedWorkerPosition) {
|
||||||
|
// Shift + Click - selects a range of rows
|
||||||
|
let start = Math.min(position, this.lastSelectedWorkerPosition);
|
||||||
|
let end = Math.max(position, this.lastSelectedWorkerPosition);
|
||||||
|
const rowsToSelect = [];
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
const currRow = this.tabulator.getRowFromPosition(i);
|
||||||
|
rowsToSelect.push(currRow);
|
||||||
|
}
|
||||||
|
tabulator.selectRow(rowsToSelect);
|
||||||
|
|
||||||
|
document.getSelection().removeAllRanges();
|
||||||
|
} else if (event.ctrlKey || event.metaKey) {
|
||||||
|
// Supports Cmd key on MacOS
|
||||||
|
// Ctrl + Click - toggles additional rows
|
||||||
|
if (tabulator.getSelectedRows().includes(row)) {
|
||||||
|
tabulator.deselectRow(row);
|
||||||
|
} else {
|
||||||
|
tabulator.selectRow(row);
|
||||||
|
}
|
||||||
|
} else if (!event.ctrlKey && !event.metaKey) {
|
||||||
|
// Regular Click - resets the selection to one row
|
||||||
|
tabulator.deselectRow(); // De-select all rows
|
||||||
|
tabulator.selectRow(row);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async onRowClick(event, row) {
|
||||||
// Take a copy of the data, so that it's decoupled from the tabulator data
|
// Take a copy of the data, so that it's decoupled from the tabulator data
|
||||||
// store. There were some issues where navigating to another worker would
|
// store. There were some issues where navigating to another worker would
|
||||||
// overwrite the old worker's ID, and this prevents that.
|
// overwrite the old worker's ID, and this prevents that.
|
||||||
const rowData = plain(row.getData());
|
|
||||||
this.$emit('tableRowClicked', rowData);
|
this.handleMultiSelect(event, row, this.tabulator);
|
||||||
|
|
||||||
|
// Update the app route, Pinia store, and component state
|
||||||
|
if (this.tabulator.getSelectedRows().includes(row)) {
|
||||||
|
// The row was toggled -> selected
|
||||||
|
const rowData = row.getData();
|
||||||
|
this._routeToWorker(rowData.id);
|
||||||
|
|
||||||
|
const worker = await this.fetchWorker(rowData.id);
|
||||||
|
this.workers.setActiveWorker(worker);
|
||||||
|
this.lastSelectedWorkerPosition = row.getPosition();
|
||||||
|
} else {
|
||||||
|
// The row was toggled -> de-selected
|
||||||
|
this._routeToWorker('');
|
||||||
|
this.workers.clearActiveWorker();
|
||||||
|
this.lastSelectedWorkerPosition = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the selected jobs according to tabulator's selected rows
|
||||||
|
this.workers.setSelectedWorkers(this.getSelectedWorkers());
|
||||||
|
},
|
||||||
|
getSelectedWorkers() {
|
||||||
|
return this.tabulator.getSelectedData();
|
||||||
},
|
},
|
||||||
toggleStatusFilter(status) {
|
toggleStatusFilter(status) {
|
||||||
const asSet = new Set(this.shownStatuses);
|
const asSet = new Set(this.shownStatuses);
|
||||||
|
@ -20,6 +20,9 @@ export const useWorkers = defineStore('workers', {
|
|||||||
|
|
||||||
/* Mapping from tag UUID to API.WorkerTag. */
|
/* Mapping from tag UUID to API.WorkerTag. */
|
||||||
tagsByID: {},
|
tagsByID: {},
|
||||||
|
|
||||||
|
/** @type {API.Worker[]} */
|
||||||
|
selectedWorkers: [],
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setActiveWorkerID(workerID) {
|
setActiveWorkerID(workerID) {
|
||||||
@ -40,12 +43,22 @@ export const useWorkers = defineStore('workers', {
|
|||||||
state.hasChanged = true;
|
state.hasChanged = true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
deselectAllWorkers() {
|
clearActiveWorker() {
|
||||||
this.$patch({
|
this.$patch({
|
||||||
activeWorker: null,
|
activeWorker: null,
|
||||||
activeWorkerID: '',
|
activeWorkerID: '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setSelectedWorkers(workers) {
|
||||||
|
this.$patch({
|
||||||
|
selectedWorkers: workers,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSelectedWorkers() {
|
||||||
|
this.$patch({
|
||||||
|
selectedWorkers: [],
|
||||||
|
});
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Fetch the available worker tags from the Manager.
|
* Fetch the available worker tags from the Manager.
|
||||||
*
|
*
|
||||||
@ -65,10 +78,13 @@ export const useWorkers = defineStore('workers', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns whether the active worker understands how to get restarted.
|
* @returns {bool} whether atleast one selected worker understands how to get restarted.
|
||||||
*/
|
*/
|
||||||
canRestart() {
|
canRestart() {
|
||||||
return !!this.activeWorker && !!this.activeWorker.can_restart;
|
if (this.selectedWorkers.length) {
|
||||||
|
return this.selectedWorkers.some((worker) => worker.can_restart);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="col col-workers-list">
|
<div class="col col-workers-list">
|
||||||
<workers-table
|
<workers-table ref="workersTable" :activeWorkerID="workerID" />
|
||||||
ref="workersTable"
|
|
||||||
:activeWorkerID="workerID"
|
|
||||||
@tableRowClicked="onTableWorkerClicked" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-workers-details">
|
<div class="col col-workers-details">
|
||||||
<worker-details :workerData="workers.activeWorker" />
|
<worker-details :workerData="workers.activeWorker" />
|
||||||
@ -32,10 +29,8 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { WorkerMgtApi } from '@/manager-api';
|
|
||||||
import { useNotifs } from '@/stores/notifications';
|
import { useNotifs } from '@/stores/notifications';
|
||||||
import { useWorkers } from '@/stores/workers';
|
import { useWorkers } from '@/stores/workers';
|
||||||
import { getAPIClient } from '@/api-client';
|
|
||||||
|
|
||||||
import NotificationBar from '@/components/footer/NotificationBar.vue';
|
import NotificationBar from '@/components/footer/NotificationBar.vue';
|
||||||
import UpdateListener from '@/components/UpdateListener.vue';
|
import UpdateListener from '@/components/UpdateListener.vue';
|
||||||
@ -54,27 +49,19 @@ export default {
|
|||||||
data: () => ({
|
data: () => ({
|
||||||
workers: useWorkers(),
|
workers: useWorkers(),
|
||||||
notifs: useNotifs(),
|
notifs: useNotifs(),
|
||||||
api: new WorkerMgtApi(getAPIClient()),
|
|
||||||
}),
|
}),
|
||||||
mounted() {
|
mounted() {
|
||||||
window.workersView = this;
|
window.workersView = this;
|
||||||
this._fetchWorker(this.workerID);
|
|
||||||
|
|
||||||
document.body.classList.add('is-two-columns');
|
document.body.classList.add('is-two-columns');
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
document.body.classList.remove('is-two-columns');
|
document.body.classList.remove('is-two-columns');
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
workerID(newWorkerID, oldWorkerID) {
|
|
||||||
this._fetchWorker(newWorkerID);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
// SocketIO connection event handlers:
|
// SocketIO connection event handlers:
|
||||||
onSIOReconnected() {
|
onSIOReconnected() {
|
||||||
this.$refs.workersTable.onReconnected();
|
this.$refs.workersTable.onReconnected();
|
||||||
this._fetchWorker(this.workerID);
|
|
||||||
},
|
},
|
||||||
onSIODisconnected(reason) {},
|
onSIODisconnected(reason) {},
|
||||||
onSIOWorkerUpdate(workerUpdate) {
|
onSIOWorkerUpdate(workerUpdate) {
|
||||||
@ -83,43 +70,18 @@ export default {
|
|||||||
if (this.$refs.workersTable) {
|
if (this.$refs.workersTable) {
|
||||||
this.$refs.workersTable.processWorkerUpdate(workerUpdate);
|
this.$refs.workersTable.processWorkerUpdate(workerUpdate);
|
||||||
}
|
}
|
||||||
if (this.workerID != workerUpdate.id) return;
|
|
||||||
|
|
||||||
if (workerUpdate.deleted_at) {
|
|
||||||
this._routeToWorker('');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._fetchWorker(this.workerID);
|
|
||||||
},
|
},
|
||||||
onSIOWorkerTagsUpdate(workerTagsUpdate) {
|
onSIOWorkerTagsUpdate(workerTagsUpdate) {
|
||||||
this.workers.refreshTags().then(() => this._fetchWorker(this.workerID));
|
if (!this.workerID) {
|
||||||
},
|
this.workers.clearActiveWorker();
|
||||||
|
|
||||||
onTableWorkerClicked(rowData) {
|
|
||||||
if (rowData.id == this.workerID) return;
|
|
||||||
this._routeToWorker(rowData.id);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} workerID worker ID to navigate to, can be empty string for "no active worker".
|
|
||||||
*/
|
|
||||||
_routeToWorker(workerID) {
|
|
||||||
const route = { name: 'workers', params: { workerID: workerID } };
|
|
||||||
this.$router.push(route);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetch worker info and set the active worker once it's received.
|
|
||||||
* @param {string} workerID worker ID, can be empty string for "no worker".
|
|
||||||
*/
|
|
||||||
_fetchWorker(workerID) {
|
|
||||||
if (!workerID) {
|
|
||||||
this.workers.deselectAllWorkers();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.api.fetchWorker(workerID).then((worker) => this.workers.setActiveWorker(worker));
|
this.workers
|
||||||
|
.refreshTags()
|
||||||
|
.then(() =>
|
||||||
|
this.api.fetchWorker(this.workerID).then((worker) => this.workers.setActiveWorker(worker))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user