diff --git a/custom_ui/api/db/tasks.py b/custom_ui/api/db/tasks.py
index 93ce9d3..adf282c 100644
--- a/custom_ui/api/db/tasks.py
+++ b/custom_ui/api/db/tasks.py
@@ -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."""
diff --git a/frontend/src/api.js b/frontend/src/api.js
index b110b4a..00acc3b 100644
--- a/frontend/src/api.js
+++ b/frontend/src/api.js
@@ -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
// ============================================================================
diff --git a/frontend/src/components/common/DataTable.vue b/frontend/src/components/common/DataTable.vue
index 96bc7a7..a3e22f3 100644
--- a/frontend/src/components/common/DataTable.vue
+++ b/frontend/src/components/common/DataTable.vue
@@ -376,6 +376,18 @@
/>
+
+
+
+
@@ -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);
};
diff --git a/frontend/src/components/pages/Tasks.vue b/frontend/src/components/pages/Tasks.vue
index 2824c68..c92c03e 100644
--- a/frontend/src/components/pages/Tasks.vue
+++ b/frontend/src/components/pages/Tasks.vue
@@ -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,