From f31ae9ac6d8d2a86d51d97d816770e8c92a52a24 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 20 Mar 2024 18:18:24 -0400 Subject: [PATCH] - Progress Commit Signed-off-by: Dave Richer --- .../task-list/task-list.component.jsx | 198 +++++++++++----- .../task-list/task-list.container.jsx | 47 +++- client/src/graphql/tasks.queries.js | 96 +++++++- .../src/pages/tasks/tasks.page.component.jsx | 2 +- hasura/metadata/actions.yaml | 10 +- hasura/metadata/allow_list.yaml | 2 +- hasura/metadata/cron_triggers.yaml | 2 +- hasura/metadata/network.yaml | 2 +- hasura/metadata/query_collections.yaml | 2 +- hasura/metadata/remote_schemas.yaml | 2 +- hasura/metadata/tables.yaml | 223 ++++++++++++++++-- 11 files changed, 488 insertions(+), 98 deletions(-) diff --git a/client/src/components/task-list/task-list.component.jsx b/client/src/components/task-list/task-list.component.jsx index bb56539a9..4a9aea817 100644 --- a/client/src/components/task-list/task-list.component.jsx +++ b/client/src/components/task-list/task-list.component.jsx @@ -1,74 +1,136 @@ -import {SyncOutlined} from "@ant-design/icons"; -import {Button, Card, Input, Space, Table, Typography} from "antd"; +import {Button, Card, Space, Switch, Table} from "antd"; import queryString from "query-string"; -import React, {useState} from "react"; +import React, {useCallback, useState} from "react"; import {useTranslation} from "react-i18next"; import {useLocation, useNavigate} from "react-router-dom"; import {pageLimit} from "../../utils/config"; +import dayjs from "../../utils/day"; +import { + CheckCircleFilled, + CheckCircleOutlined, + DeleteFilled, + DeleteOutlined, ExclamationCircleFilled, + SyncOutlined +} from "@ant-design/icons"; + +const DueDateRecord = ({dueDate}) => { + if (dueDate) { + const dueDateFormatted = dayjs(dueDate).format("YYYY-MM-DD"); + const relativeDueDate = dayjs(dueDate).fromNow(); + const today = dayjs().format("YYYY-MM-DD"); + if (dueDateFormatted < today) { + return
{dueDateFormatted}
; + } else { + return
{dueDateFormatted}
; + } + } else { + return
N/A
; + } +} +const PriorityLabel = ({priority}) => { + switch(priority) { + case 1: + return
+ High +
; + case 2: + return
+ Medium +
; + case 3: + return
+ Low +
; + default: + return
+ None +
; + } +} export default function TaskListComponent({ loading, tasks, total, refetch, + toggleCompletedStatus, }) { + const {t} = useTranslation(); + const search = queryString.parse(useLocation().search); + + // Extract Query Params const { page, - // sortcolumn, sortorder + sortcolumn, + sortorder, + deleted, + completed } = search; + const history = useNavigate(); - const [state, setState] = useState({ - sortedInfo: {}, - filteredInfo: {text: ""}, - }); - - const {t} = useTranslation(); - const columns = [ { title: t("tasks.fields.title"), dataIndex: "title", key: "title", + sorter: true, + sortOrder: sortcolumn === "title" && sortorder, }, { title: t("tasks.fields.description"), dataIndex: "description", key: "description", + sorter: true, + sortOrder: sortcolumn === "description" && sortorder, }, { title: t("tasks.fields.due_date"), dataIndex: "due_date", key: "due_date", - }, - { - title: t("tasks.fields.assigned_to"), - dataIndex: "assigned_to", - key: "assigned_to", - }, - { - title: t("tasks.fields.completed"), - dataIndex: "completed", - key: "completed", - }, - { - title: t("tasks.fields.completed_at"), - dataIndex: "completed_at", - key: "completed_at", - }, - { - title: t("tasks.fields.remind_at"), - dataIndex: "remind_at", - key: "remind_at", + sorter: true, + sortOrder: sortcolumn === "due_date" && sortorder, + width: '5%', + render: (text, record) => , }, { title: t("tasks.fields.priority"), dataIndex: "priority", key: "priority", + sorter: true, + sortOrder: sortcolumn === "priority" && sortorder, + width: '5%', + render: (text, record) => + }, + { + title: t("tasks.fields.actions"), + key: "toggleCompleted", + width: '5%', + render: (text, record) => ( + + + + + ), }, ]; + const [state, setState] = useState({ + sortedInfo: {}, + filteredInfo: {text: ""}, + }); + + // Columns definition remains the same + const handleTableChange = (pagination, filters, sorter) => { setState({...state, filteredInfo: filters, sortedInfo: sorter}); search.page = pagination.current; @@ -76,43 +138,49 @@ export default function TaskListComponent({ search.sortorder = sorter.order; history({search: queryString.stringify(search)}); }; + + const handleSwitchChange = (param, value) => { + if (value) { + search[param] = "true"; + } else { + delete search[param]; + } + history({search: queryString.stringify(search)}); + }; + + /** + * Extra actions for the tasks + * @type {Function} + */ + const tasksExtra = useCallback(() => { + return ( + + } + unCheckedChildren={} + title={t('tasks.titles.completed')} + checked={completed === "true"} + onChange={(value) => handleSwitchChange('completed', value)} + /> + } + unCheckedChildren={} + title={t('tasks.titles.deleted')} + checked={deleted === "true"} + onChange={(value) => handleSwitchChange('deleted', value)} + /> + + + ); + }, [refetch, deleted, completed]); + return ( - {search.search && ( - <> - - {t("general.labels.searchresults", {search: search.search})} - - - - )} - - { - if (value?.length >= 3) { - search.search = value; - } else { - delete search.search; - } - history({search: queryString.stringify(search)}); - }} - enterButton - /> - - } + extra={tasksExtra()} > { + const completed_at = !currentStatus ? new Date().toISOString() : null; + await toggleTaskCompleted({ + variables: { + id: id, + completed: !currentStatus, + completed_at: completed_at + } + }); + refetch(); + }; + + const [toggleTaskDeleted] = useMutation(MUTATION_TOGGLE_TASK_DELETED); + + const toggleDeletedStatus = async (id, currentStatus) => { + const deleted_at = !currentStatus ? new Date().toISOString() : null; + await toggleTaskDeleted({ + variables: { + id: id, + deleted: !currentStatus, + deleted_at: deleted_at + } + }); + refetch(); + }; if (error) return ; @@ -39,6 +74,8 @@ export default function TaskListContainer() { tasks={data ? data.tasks : null} total={data ? data.tasks_aggregate.aggregate.count : 0} refetch={refetch} + toggleCompletedStatus={toggleCompletedStatus} + toggleDeletedStatus={toggleDeletedStatus} /> ); } diff --git a/client/src/graphql/tasks.queries.js b/client/src/graphql/tasks.queries.js index 5ddaef3c1..0a4375b1d 100644 --- a/client/src/graphql/tasks.queries.js +++ b/client/src/graphql/tasks.queries.js @@ -1,5 +1,9 @@ import {gql} from "@apollo/client"; +/** + * All tasks paginated query + * @type {DocumentNode} + */ export const QUERY_ALL_TASKS_PAGINATED = gql` query QUERY_ALL_TASKS_PAGINATED( $offset: Int @@ -30,10 +34,98 @@ export const QUERY_ALL_TASKS_PAGINATED = gql` partsorderid billid } - tasks_aggregate(args: {}) { + tasks_aggregate { aggregate { - count(distinct: true) + count } } } `; + +/** + * My tasks paginated query + * @type {DocumentNode} + */ +export const QUERY_MY_TASKS_PAGINATED = gql` + query QUERY_TASKS_PAGINATED( + $offset: Int + $limit: Int + $user: String! + $bodyshop: uuid! + $deleted: Boolean + $completed: Boolean + $order: [tasks_order_by!]! + ) { + tasks( + offset: $offset + limit: $limit + order_by: $order + where: { + assigned_to: {_eq: $user}, + bodyshopid: {_eq: $bodyshop}, + deleted: {_eq: $deleted}, + completed: {_eq: $completed} + } + ) { + id + created_at + updated_at + title + description + deleted + deleted_at + due_date + created_by + assigned_to + completed + completed_at + remind_at + priority + jobid + joblineid + partsorderid + billid + bodyshopid + } + tasks_aggregate( + where: { + assigned_to: {_eq: $user}, + bodyshopid: {_eq: $bodyshop}, + deleted: {_eq: $deleted}, + completed: {_eq: $completed} + } + ) { + aggregate { + count + } + } + } +`; + +/** + * Toggle task completed mutation + * @type {DocumentNode} + */ +export const MUTATION_TOGGLE_TASK_COMPLETED = gql` + mutation MUTATION_TOGGLE_TASK_COMPLETED($id: uuid!, $completed: Boolean!, $completed_at: timestamptz) { + update_tasks_by_pk(pk_columns: {id: $id}, _set: {completed: $completed, completed_at: $completed_at}) { + id + completed + completed_at + } + } +`; + +/** + * Toggle task deleted mutation + * @type {DocumentNode} + */ +export const MUTATION_TOGGLE_TASK_DELETED = gql` + mutation MUTATION_TOGGLE_TASK_DELETED($id: uuid!, $deleted: Boolean!, $deleted_at: timestamptz) { + update_tasks_by_pk(pk_columns: {id: $id}, _set: {deleted: $deleted, deleted_at: $deleted_at}) { + id + deleted + deleted_at + } + } +`; diff --git a/client/src/pages/tasks/tasks.page.component.jsx b/client/src/pages/tasks/tasks.page.component.jsx index d1b80c856..253bc9c4c 100644 --- a/client/src/pages/tasks/tasks.page.component.jsx +++ b/client/src/pages/tasks/tasks.page.component.jsx @@ -5,7 +5,7 @@ export default function TasksPageComponent({bodyshop, currentUser}) { return (
- +
); } diff --git a/hasura/metadata/actions.yaml b/hasura/metadata/actions.yaml index f5639566d..1edb4c2ff 100644 --- a/hasura/metadata/actions.yaml +++ b/hasura/metadata/actions.yaml @@ -1,6 +1,6 @@ -actions: [ ] +actions: [] custom_types: - enums: [ ] - input_objects: [ ] - objects: [ ] - scalars: [ ] + enums: [] + input_objects: [] + objects: [] + scalars: [] diff --git a/hasura/metadata/allow_list.yaml b/hasura/metadata/allow_list.yaml index 1e3ec7217..fe51488c7 100644 --- a/hasura/metadata/allow_list.yaml +++ b/hasura/metadata/allow_list.yaml @@ -1 +1 @@ -[ ] +[] diff --git a/hasura/metadata/cron_triggers.yaml b/hasura/metadata/cron_triggers.yaml index 1e3ec7217..fe51488c7 100644 --- a/hasura/metadata/cron_triggers.yaml +++ b/hasura/metadata/cron_triggers.yaml @@ -1 +1 @@ -[ ] +[] diff --git a/hasura/metadata/network.yaml b/hasura/metadata/network.yaml index ffcd4415b..0967ef424 100644 --- a/hasura/metadata/network.yaml +++ b/hasura/metadata/network.yaml @@ -1 +1 @@ -{ } +{} diff --git a/hasura/metadata/query_collections.yaml b/hasura/metadata/query_collections.yaml index 1e3ec7217..fe51488c7 100644 --- a/hasura/metadata/query_collections.yaml +++ b/hasura/metadata/query_collections.yaml @@ -1 +1 @@ -[ ] +[] diff --git a/hasura/metadata/remote_schemas.yaml b/hasura/metadata/remote_schemas.yaml index 1e3ec7217..fe51488c7 100644 --- a/hasura/metadata/remote_schemas.yaml +++ b/hasura/metadata/remote_schemas.yaml @@ -1 +1 @@ -[ ] +[] diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 9cc14dd54..38dff43fa 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -53,7 +53,7 @@ update_permissions: - role: user permission: - columns: [ ] + columns: [] filter: jobline: job: @@ -569,6 +569,13 @@ table: name: parts_orders schema: public + - name: tasks + using: + foreign_key_constraint_on: + column: billid + table: + name: tasks + schema: public insert_permissions: - role: user permission: @@ -698,7 +705,7 @@ value_from_env: EVENT_SECRET request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/opensearch' version: 2 @@ -818,6 +825,13 @@ table: name: inventory schema: public + - name: ioevents + using: + foreign_key_constraint_on: + column: bodyshopid + table: + name: ioevents + schema: public - name: jobs using: foreign_key_constraint_on: @@ -846,6 +860,13 @@ table: name: phonebook schema: public + - name: tasks + using: + foreign_key_constraint_on: + column: bodyshopid + table: + name: tasks + schema: public - name: timetickets using: foreign_key_constraint_on: @@ -1653,7 +1674,7 @@ columns: - config - id - filter: { } + filter: {} limit: 1 - role: user permission: @@ -2491,7 +2512,7 @@ - effective_date - end_date - content - filter: { } + filter: {} - table: name: exportlog schema: public @@ -2675,6 +2696,13 @@ - table: name: ioevents schema: public + object_relationships: + - name: bodyshop + using: + foreign_key_constraint_on: bodyshopid + - name: user + using: + foreign_key_constraint_on: useremail - table: name: job_ar_schema schema: public @@ -2824,6 +2852,13 @@ table: name: parts_order_lines schema: public + - name: tasks + using: + foreign_key_constraint_on: + column: joblineid + table: + name: tasks + schema: public insert_permissions: - role: user permission: @@ -3311,6 +3346,13 @@ table: name: scoreboard schema: public + - name: tasks + using: + foreign_key_constraint_on: + column: jobid + table: + name: tasks + schema: public - name: timetickets using: foreign_key_constraint_on: @@ -4200,13 +4242,13 @@ interval_sec: 10 num_retries: 0 timeout_sec: 60 - webhook: https://worktest.home.irony.online + webhook_from_env: HASURA_API_URL headers: - name: event-secret value_from_env: EVENT_SECRET request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/job/statustransition' version: 2 @@ -4220,7 +4262,7 @@ webhook_from_env: HASURA_API_URL request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/record-handler/arms' version: 2 @@ -4243,7 +4285,7 @@ value_from_env: EVENT_SECRET request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/opensearch' version: 2 @@ -4256,13 +4298,13 @@ columns: - key - value - filter: { } + filter: {} - role: user permission: columns: - key - value - filter: { } + filter: {} - table: name: messages schema: public @@ -4694,7 +4736,7 @@ value_from_env: EVENT_SECRET request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/opensearch' version: 2 @@ -5008,6 +5050,13 @@ table: name: parts_order_lines schema: public + - name: tasks + using: + foreign_key_constraint_on: + column: partsorderid + table: + name: tasks + schema: public insert_permissions: - role: user permission: @@ -5302,7 +5351,7 @@ value_from_env: EVENT_SECRET request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/opensearch' version: 2 @@ -5623,6 +5672,129 @@ _eq: X-Hasura-User-Id - active: _eq: true +- table: + name: tasks + schema: public + object_relationships: + - name: bill + using: + foreign_key_constraint_on: billid + - name: bodyshop + using: + foreign_key_constraint_on: bodyshopid + - name: job + using: + foreign_key_constraint_on: jobid + - name: jobline + using: + foreign_key_constraint_on: joblineid + - name: parts_order + using: + foreign_key_constraint_on: partsorderid + - name: user + using: + foreign_key_constraint_on: assigned_to + - name: userByCreatedBy + using: + foreign_key_constraint_on: created_by + insert_permissions: + - role: user + permission: + check: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + columns: + - completed + - deleted + - priority + - assigned_to + - created_by + - description + - title + - completed_at + - created_at + - deleted_at + - due_date + - remind_at + - updated_at + - billid + - bodyshopid + - id + - jobid + - joblineid + - partsorderid + select_permissions: + - role: user + permission: + columns: + - completed + - deleted + - priority + - assigned_to + - created_by + - description + - title + - completed_at + - created_at + - deleted_at + - due_date + - remind_at + - updated_at + - billid + - bodyshopid + - id + - jobid + - joblineid + - partsorderid + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + allow_aggregations: true + update_permissions: + - role: user + permission: + columns: + - completed + - deleted + - priority + - assigned_to + - created_by + - description + - title + - completed_at + - created_at + - deleted_at + - due_date + - remind_at + - updated_at + - billid + - bodyshopid + - id + - jobid + - joblineid + - partsorderid + filter: + bodyshop: + associations: + _and: + - user: + authid: + _eq: X-Hasura-User-Id + - active: + _eq: true + check: null - table: name: timetickets schema: public @@ -5843,7 +6015,7 @@ - user: authid: _eq: X-Hasura-User-Id - check: { } + check: {} - table: name: tt_approval_queue schema: public @@ -6006,6 +6178,13 @@ table: name: exportlog schema: public + - name: ioevents + using: + foreign_key_constraint_on: + column: useremail + table: + name: ioevents + schema: public - name: messages using: foreign_key_constraint_on: @@ -6034,6 +6213,20 @@ table: name: parts_orders schema: public + - name: tasks + using: + foreign_key_constraint_on: + column: assigned_to + table: + name: tasks + schema: public + - name: tasksByCreatedBy + using: + foreign_key_constraint_on: + column: created_by + table: + name: tasks + schema: public - name: timetickets using: foreign_key_constraint_on: @@ -6051,7 +6244,7 @@ insert_permissions: - role: user permission: - check: { } + check: {} columns: - authid - email @@ -6253,7 +6446,7 @@ value_from_env: EVENT_SECRET request_transform: method: POST - query_params: { } + query_params: {} template_engine: Kriti url: '{{$base_url}}/opensearch' version: 2