Added a Select component to the Actions section of the Datatable, and API methods to load the available status-es from the Task doctype to populate the select for the tasks list.

This commit is contained in:
rocketdebris 2026-01-13 16:39:52 -05:00
parent adb7bc5930
commit 0c52f3fc23
4 changed files with 88 additions and 7 deletions

View File

@ -13,6 +13,23 @@ def get_job_task_list(job_id=""):
return build_error_response(str(e), 500)
@frappe.whitelist()
def get_task_status_options():
print("DEBUG: Getting task status options")
try:
task_doctype = frappe.get_doc("DocType", "Task")
status_index = 0
for i, field in enumerate(task_doctype.fields):
if field.fieldname == "status":
status_index = i
break
options = task_doctype.fields[status_index].options.split()
print("DEBUG: Task Status options retreived", options)
return build_success_response(options)
except Exception as e:
return build_error_response(str(e), 500)
@frappe.whitelist()
def get_tasks_table_data(filters={}, sortings=[], page=1, page_size=10):
"""Get paginated task table data with filtering and sorting support."""

View File

@ -23,6 +23,7 @@ const FRAPPE_GET_INSTALL_PROJECTS_METHOD = "custom_ui.api.db.jobs.get_install_pr
const FRAPPE_GET_JOB_TEMPLATES_METHOD = "custom_ui.api.db.jobs.get_job_templates";
// Task methods
const FRAPPE_GET_TASKS_METHOD = "custom_ui.api.db.tasks.get_tasks_table_data";
const FRAPPE_GET_TASKS_STATUS_OPTIONS = "custom_ui.api.db.tasks.get_task_status_options";
// Invoice methods
const FRAPPE_GET_INVOICES_METHOD = "custom_ui.api.db.invoices.get_invoice_table_data";
const FRAPPE_UPSERT_INVOICE_METHOD = "custom_ui.api.db.invoices.upsert_invoice";
@ -384,6 +385,12 @@ class Api {
return result;
}
static async getTaskStatusOptions() {
console.log("DEBUG: API - Loading Task Status options form the backend.");
const result = await this.request(FRAPPE_GET_TASKS_STATUS_OPTIONS, {});
return result
}
// ============================================================================
// INVOICE / PAYMENT METHODS
// ============================================================================

View File

@ -376,6 +376,18 @@
/>
<!-- Dropdown menu would go here - could be implemented with PrimeVue Menu component -->
</div>
<!-- Select menu for a single action with multiple options -->
<div
v-if="rowActionsGrouped.select.length > 0"
class="dt-row-actions-select"
>
<Select
v-for="action in rowActionsGrouped.select"
:options="action.statusOptions"
:placeholder="action.label"
@change="handleSelectChange(action, slotProps.data, $event)"
/>
</div>
</div>
</template>
</Column>
@ -387,6 +399,7 @@ import DataTable from "primevue/datatable";
import Column from "primevue/column";
import Tag from "primevue/tag";
import Button from "primevue/button";
import Select from "primevue/select";
import InputText from "primevue/inputtext";
import { FilterMatchMode } from "@primevue/core";
import { useFiltersStore } from "../../stores/filters";
@ -701,6 +714,7 @@ const rowActionsGrouped = computed(() => {
),
secondary: rowActions.value.filter((action) => action.layout?.priority === "secondary"),
dropdown: rowActions.value.filter((action) => action.layout?.priority === "dropdown"),
select: rowActions.value.filter((action) => action.layout?.priority === "select"),
};
return groups;
});
@ -1018,6 +1032,22 @@ const handleActionClick = (action, rowData = null) => {
}
};
const handleSelectChange = (action, rowData, event) => {
try {
if (typeof action.action === "function") {
if (rowData) {
// Row-specific action - pass row data
action.action(rowData, event.value);
} else {
// Global action - no row data needed
action.action();
}
}
} catch (error) {
console.error("Error executing action:", error);
}
}
const handleGlobalAction = (action) => {
handleActionClick(action);
};

View File

@ -36,6 +36,8 @@ const notifications = useNotificationStore();
const tableData = ref([]);
const totalRecords = ref(0);
const isLoading = ref(false);
const showCompleted = ref(false);
const statusOptions = ref([]);
// Computed property to get current filters for the chart
const currentFilters = computed(() => {
@ -63,6 +65,29 @@ const filterBy = (filter) => {
console.log("DEBUG: Tasks filterBy not implemented yet.");
};
const tableActions = [
{
label: "Show Completed",
action: () => {
showCompleted = !showCompleted
},
type: "button",
style: "info",
},
{
label: "Set Status",
action: (rowData, newValue) => {
console.log("DEBUG: Row Data:", rowData);
console.log("DEBUG: New Value:", newValue);
},
rowAction: true,
layout: {
priority: "select"
},
statusOptions: statusOptions.value
},
];
// Handle lazy loading events from DataTable
const handleLazyLoad = async (event) => {
console.log("Tasks page - handling lazy load:", event);
@ -154,13 +179,11 @@ const handlePropertyClick = (link, rowData) => {
// router.push(`/task?taskId=${rowData.name}`);
//}
watch(
() => filtersStore.getTableFilters("clients"),
async () => {
await refreshStatusCounts();
},
{ deep: true },
);
watch(showCompleted, () => {
if (showCompleted) {
// TODO: Logic for filtering on "Completed" goes here
}
});
// Load initial data
onMounted(async () => {
@ -175,6 +198,10 @@ onMounted(async () => {
const initialFilters = filtersStore.getTableFilters("tasks");
const initialSorting = filtersStore.getTableSorting("tasks");
const optionsResult = await Api.getTaskStatusOptions();
statusOptions.value = optionsResult;
console.log("DEBUG: Loaded Status options: ", statusOptions.value)
await handleLazyLoad({
page: initialPagination.page,
rows: initialPagination.rows,