Fix: Tag Interface Delete Button #104256

Manually merged
Sybren A. Stüvel merged 39 commits from Evelinealy/flamenco:tag-interface into main 2023-11-02 16:13:14 +01:00
Showing only changes of commit 77a08c4254 - Show all commits

View File

@ -2,11 +2,11 @@
<div class="col col-workers-list"> <div class="col col-workers-list">
<h2 class="column-title">Tag Details</h2> <h2 class="column-title">Tag Details</h2>
<div class="action-buttons"> <div class="action-buttons btn-bar-group">
<div class="btn-bar">
<button @click="fetchTags">Refresh</button> <button @click="fetchTags">Refresh</button>
<button @click="deleteTag" :disabled="tags.length === 0"> <button @click="deleteTag" :disabled="!selectedTag">Delete Tag</button>
Delete Tag </div>
</button>
</div> </div>
<div class="action-buttons"> <div class="action-buttons">
@ -21,103 +21,17 @@
</form> </form>
</div> </div>
<!-- Table to display tags --> <div id="tag-table-container"></div>
<table v-if="tags.length > 0" class="tag-table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr
v-for="tag in tags"
:key="tag.name"
@click="onTagClick(tag)"
:class="{ selected: isSelected(tag) }"
>
<td>{{ tag.name }}</td>
<td>{{ tag.description }}</td>
<!-- Name editing field -->
<td>
<input
type="text"
v-if="isSelected(tag)"
v-model="tag.name"
@blur="updateTagName(tag)"
/>
<span v-else>{{ tag.name }}</span>
</td>
</tr>
</tbody>
</table>
<div v-else class="dl-no-data">
<span>No tags found.</span>
</div>
</div> </div>
<footer class="app-footer"></footer> <footer class="app-footer"></footer>
</template> </template>
<style scoped> <style scoped>
.action-buttons { @import "@/assets/base.css";
margin-bottom: 10px;
margin-top: 10px;
}
.action-buttons button {
margin-right: 10px;
}
/* Add some basic styling to the table */
.tag-table {
background-color: var(--table-color-background-row-odd);
border-radius: var(--border-radius);
color: var(--color-text-muted);
font-family: var(--font-family-mono);
font-size: var(--font-size-sm);
text-align: left;
width: 100%;
border-collapse: collapse;
margin-top: 20px;
overflow: hidden;
position: relative;
text-align: left;
transform: translateZ(0);
}
.tag-table th {
height: 24px;
white-space: nowrap;
}
.tag-table td {
border: 1px solid #ccc;
padding: 8px;
text-align: left;
}
.tag-table th {
background-color: #f0f0f0;
}
.tag-table tbody tr:hover {
background-color: #f5f5f5;
}
/* Style for selected row */
.tag-table tbody tr.selected {
background-color: rgb(137, 130, 201);
font-weight: bold;
}
.selected {
background-color: #f0f0f0;
}
</style> </style>
<script> <script>
import { TabulatorFull as Tabulator } from "tabulator-tables";
import { useWorkers } from "@/stores/workers"; import { useWorkers } from "@/stores/workers";
import { useNotifs } from "@/stores/notifications"; import { useNotifs } from "@/stores/notifications";
import { WorkerMgtApi } from "@/manager-api"; import { WorkerMgtApi } from "@/manager-api";
@ -137,22 +51,56 @@ export default {
selectedTag: null, selectedTag: null,
newTagName: "", newTagName: "",
workers: useWorkers(), workers: useWorkers(),
activeRowIndex: -1,
}; };
}, },
mounted() { mounted() {
this.fetchTags(); this.fetchTags();
const vueComponent = this;
const api = new WorkerMgtApi(getAPIClient()); const api = new WorkerMgtApi(getAPIClient());
window.api = api; window.api = api;
const tag_options = {
columns: [
{ title: "Name", field: "name", sorter: "string" },
{ title: "Description", field: "description", sorter: "string" },
],
rowFormatter(row) {
const data = row.getData();
const isActive = data.id === vueComponent.activeTagID;
const classList = row.getElement().classList;
classList.toggle("active-row", isActive);
classList.toggle("deletion-requested", !!data.delete_requested_at);
},
layout: "fitData",
layoutColumnsOnNewData: true,
height: "525px", // Must be set in order for the virtual DOM to function correctly.
selectable: true, // The active worker is tracked by click events, not row selection.
};
this.tabulator = new Tabulator("#tag-table-container", tag_options);
this.tabulator.on("rowClick", this.onRowClick);
this.tabulator.on("tableBuilt", () => {
this.fetchTags();
});
}, },
methods: { methods: {
sortData() {
const tab = this.tabulator;
tab.setSort(tab.getSorters()); // This triggers re-sorting.
},
_onTableBuilt() {
this.fetchTags();
},
fetchTags() { fetchTags() {
this.workers this.workers
.refreshTags() .refreshTags()
.then(() => { .then(() => {
this.tags = this.workers.tags; this.tags = this.workers.tags;
this.tabulator.setData(this.tags);
}) })
.catch((error) => { .catch((error) => {
const errorMsg = JSON.stringify(error); const errorMsg = JSON.stringify(error);
@ -168,7 +116,9 @@ export default {
api api
.createWorkerTag(newTag) .createWorkerTag(newTag)
.then(this.fetchTags) .then(() => {
this.fetchTags(); // Refresh table data
})
.catch((error) => { .catch((error) => {
const errorMsg = JSON.stringify(error); const errorMsg = JSON.stringify(error);
useNotifs().add(`Error: ${errorMsg}`); useNotifs().add(`Error: ${errorMsg}`);
@ -176,34 +126,40 @@ export default {
}, },
deleteTag() { deleteTag() {
if (this.tags.length === 0) {
return;
}
if (!this.selectedTag) { if (!this.selectedTag) {
return; return;
} }
// Find the index of the selected tag in the tags array
const api = new WorkerMgtApi(getAPIClient());
api
.deleteWorkerTag(this.selectedTag.id)
.then(() => {
const index = this.tags.findIndex( const index = this.tags.findIndex(
dr.sybren marked this conversation as resolved Outdated

Add this column to the end, so that it has the same layout as the job blocklist (there the is on the right as well).

Add this column to the end, so that it has the same layout as the job blocklist (there the ❌ is on the right as well).
(tag) => tag.id === this.selectedTag.id (tag) => tag.id === this.selectedTag.id
); );
if (index !== -1) { if (index !== -1) {
const api = new WorkerMgtApi(getAPIClient());
api
.deleteWorkerTag(this.selectedTag.id)
.then(() => {
this.tags.splice(index, 1); this.tags.splice(index, 1);
}
this.selectedTag = null; this.selectedTag = null;
this.tabulator.setData(this.tags);
}) })
.catch((error) => { .catch((error) => {
const errorMsg = JSON.stringify(error); const errorMsg = JSON.stringify(error);
useNotifs().add(`Error: ${errorMsg}`); useNotifs().add(`Error: ${errorMsg}`);
}); });
}
}, },
onTagClick(tag) { onRowClick(event, row) {
this.selectedTag = tag; const tag = row.getData();
this.onTagClick(tag, row.getIndex());
},
onTagClick(tag, rowIndex) {
console.log("Clicked Tag:", tag);
console.log("Selected Tag:", this.selectedTag);
this.selectedTag = this.selectedTag === tag ? null : tag;
this.activeRowIndex = rowIndex;
}, },
}, },