Learn more about the useTasks
hook.
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/* * Copyright 2025 Palantir Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import useSWR from "swr"; import { useOsdkClient } from "@osdk/react"; import { OsdkITask } from "@advanced-to-do-application/sdk"; import { IProject } from "./useProjects"; import { useCallback, useEffect, useState } from "react"; import useAdmin from "./useAdmin"; import _ from "lodash"; import type { User } from "@osdk/foundry.admin"; import type { InterfaceMetadata } from "@osdk/api"; export interface ITask { osdkTask: OsdkITask.OsdkInstance; createdBy: User; assignedTo: User; } function useTasks(project: IProject) { const client = useOsdkClient(); const [metadata, setMetadata] = useState<InterfaceMetadata>(); const { getBatchUserDetails } = useAdmin(); // `$includeAllBaseObjectProperties: true,` means that although we are fetching the object through its interface implementation, // we are still going to get all the base object properties; when we pivot to the base object using $as, we don not need to fetch them again. const fetcher = useCallback(async () => { const tasksPage = await client(OsdkITask).where({ projectId: { $eq: project.$primaryKey }, }).fetchPage({ $includeAllBaseObjectProperties: true, $orderBy: { "dueDate": "desc", "status": "asc" }, }); // Get the user details for the createdBy field. const createdByIds = _.uniq(tasksPage.data.map((task) => task.createdBy as string)); const createdByUserList = await getBatchUserDetails(createdByIds); // Get the user details for the assignedTo field. const assignedToIds = _.uniq(tasksPage.data.map((task) => task.assignedTo as string)); const assignedToUserList = await getBatchUserDetails(assignedToIds); const tasksList: ITask[] = tasksPage.data.map((task) => ({ osdkTask: task, assignedTo: assignedToUserList[task.assignedTo as string], createdBy: createdByUserList[task.createdBy as string], })); return tasksList; } , [getBatchUserDetails, project.$primaryKey, client]); const { data, isLoading, isValidating, error, mutate } = useSWR<ITask[]>( ["tasks",project.$primaryKey], fetcher, { revalidateOnFocus: false } ); // This shows how we read the object type metadata and use the property display name from the ontology. const getObjectTypeMetadata = useCallback(async () => { const objectTypeMetadata = await client.fetchMetadata(OsdkITask); setMetadata(objectTypeMetadata); } , [client]); useEffect(() => { getObjectTypeMetadata(); }, [getObjectTypeMetadata]); useEffect(() => { // Subscribe to the object set to get real-time updates. const subscription = client(OsdkITask) .where({ projectId: { $eq: project.$primaryKey }, }) .subscribe( { onChange(update) { if (update.state === "ADDED_OR_UPDATED") { // An object has received an update or an object was added to the object set. const currentObject = data?.find((task) => task.osdkTask.$primaryKey === update.object.$primaryKey); if (currentObject !== undefined) { // Get the user details for the createdBy field and the assignedTo field. getBatchUserDetails([update.object.createdBy as string, update.object.assignedTo as string]).then((userList) => { const updatedObject: ITask = { osdkTask: update.object, assignedTo: userList[update.object.assignedTo as string], createdBy: userList[update.object.createdBy as string], }; // Replace the object in date with the new one to mutate without fetching. mutate((currentData: ITask[] | undefined) => { if (!currentData) return []; return currentData.map((task) => task.osdkTask.$primaryKey === update.object.$primaryKey ? updatedObject : task); }, { revalidate: false }); }); } } else if (update.state === "REMOVED") { // remove the object from the data mutate without fetching. mutate((currentData: ITask[] | undefined) => { if (!currentData) return []; return currentData.filter((task) => task.osdkTask.$primaryKey !== update.object.$primaryKey); }, { revalidate: false }); } }, onSuccessfulSubscription() { // The subscription was successful and you can expect to receive updates. }, onError(err) { // There was an error with the subscription and you will not receive any more updates. console.error(err); }, onOutOfDate() { // We could not keep track of all changes. Reload the objects in your set. }, }, ); subscription.unsubscribe(); },[data, getBatchUserDetails, mutate, project.$primaryKey, client]); return { tasks: data ?? [], isLoading, isValidating, isError: error, metadata, }; } export default useTasks;