@@ -139,7 +139,7 @@ function getNavItems(organizationId?: string): NavItem[] {
|
|||||||
title: "Tasks",
|
title: "Tasks",
|
||||||
icon: Inbox,
|
icon: Inbox,
|
||||||
url: organizationId
|
url: organizationId
|
||||||
? `/organizations/${organizationId}/dashboard`
|
? `/organizations/${organizationId}/tasks`
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,12 +27,14 @@ import { ListRiskPage } from "./risks/ListRiskPage";
|
|||||||
import ShowRiskView from "./risks/ShowRiskView";
|
import ShowRiskView from "./risks/ShowRiskView";
|
||||||
import { ListVendorPage } from "./vendors/ListVendorPage";
|
import { ListVendorPage } from "./vendors/ListVendorPage";
|
||||||
import { VendorPage } from "./vendors/VendorPage";
|
import { VendorPage } from "./vendors/VendorPage";
|
||||||
|
import { ListTaskPage } from "./tasks/ListTaskPage";
|
||||||
|
|
||||||
export function OrganizationsRoutes() {
|
export function OrganizationsRoutes() {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path=":organizationId/*" element={<OrganizationLayout />}>
|
<Route path=":organizationId/*" element={<OrganizationLayout />}>
|
||||||
<Route index element={<HomePage />} />
|
<Route index element={<HomePage />} />
|
||||||
|
<Route path="tasks" element={<ListTaskPage />} />
|
||||||
<Route path="people" element={<PeopleListPage />} />
|
<Route path="people" element={<PeopleListPage />} />
|
||||||
<Route path="people/new" element={<NewPeoplePage />} />
|
<Route path="people/new" element={<NewPeoplePage />} />
|
||||||
<Route path="people/:peopleId" element={<PeoplePage />} />
|
<Route path="people/:peopleId" element={<PeoplePage />} />
|
||||||
|
|||||||
@@ -982,6 +982,7 @@ function MeasureViewContent({
|
|||||||
variables: {
|
variables: {
|
||||||
connections: [`${data.measure.tasks?.__id}`],
|
connections: [`${data.measure.tasks?.__id}`],
|
||||||
input: {
|
input: {
|
||||||
|
organizationId: organizationId!,
|
||||||
measureId: data.measure.id,
|
measureId: data.measure.id,
|
||||||
name: newTaskName,
|
name: newTaskName,
|
||||||
description: newTaskDescription,
|
description: newTaskDescription,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<f037ead461a7a59d39f2e98140e4c72f>>
|
* @generated SignedSource<<b53893b96884bbc49ad8f2dbdb22e2ea>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -13,8 +13,9 @@ export type TaskState = "DONE" | "TODO";
|
|||||||
export type CreateTaskInput = {
|
export type CreateTaskInput = {
|
||||||
assignedToId?: string | null | undefined;
|
assignedToId?: string | null | undefined;
|
||||||
description: string;
|
description: string;
|
||||||
measureId: string;
|
measureId?: string | null | undefined;
|
||||||
name: string;
|
name: string;
|
||||||
|
organizationId: string;
|
||||||
timeEstimate?: any | null | undefined;
|
timeEstimate?: any | null | undefined;
|
||||||
};
|
};
|
||||||
export type MeasureViewCreateTaskMutation$variables = {
|
export type MeasureViewCreateTaskMutation$variables = {
|
||||||
|
|||||||
43
apps/console/src/pages/organizations/tasks/ListTaskPage.tsx
Normal file
43
apps/console/src/pages/organizations/tasks/ListTaskPage.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { PageTemplateSkeleton } from "@/components/PageTemplate";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
import { lazy } from "@probo/react-lazy";
|
||||||
|
import { useLocation } from "react-router";
|
||||||
|
import { ErrorBoundaryWithLocation } from "../ErrorBoundary";
|
||||||
|
|
||||||
|
const ListTaskView = lazy(() => import("./ListTaskView"));
|
||||||
|
|
||||||
|
export function ListTaskViewSkeleton() {
|
||||||
|
return (
|
||||||
|
<PageTemplateSkeleton title="Tasks">
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="rounded-xl border bg-level-1 p-4 space-y-4">
|
||||||
|
<div className="h-5 w-32 subtle-bg animate-pulse rounded" />
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div className="h-10 flex-1 subtle-bg animate-pulse rounded" />
|
||||||
|
<div className="h-10 w-32 subtle-bg animate-pulse rounded" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{[1, 2, 3].map((i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="h-[72px] subtle-bg animate-pulse rounded-xl"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageTemplateSkeleton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ListTaskPage() {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense key={location.pathname} fallback={<ListTaskViewSkeleton />}>
|
||||||
|
<ErrorBoundaryWithLocation>
|
||||||
|
<ListTaskView />
|
||||||
|
</ErrorBoundaryWithLocation>
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
888
apps/console/src/pages/organizations/tasks/ListTaskView.tsx
Normal file
888
apps/console/src/pages/organizations/tasks/ListTaskView.tsx
Normal file
@@ -0,0 +1,888 @@
|
|||||||
|
import { Suspense, useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
useQueryLoader,
|
||||||
|
graphql,
|
||||||
|
PreloadedQuery,
|
||||||
|
usePreloadedQuery,
|
||||||
|
useMutation,
|
||||||
|
useRelayEnvironment,
|
||||||
|
fetchQuery,
|
||||||
|
} from "react-relay";
|
||||||
|
import { useSearchParams, useParams } from "react-router";
|
||||||
|
import { PageTemplate } from "@/components/PageTemplate";
|
||||||
|
import { ListTaskViewSkeleton } from "./ListTaskPage";
|
||||||
|
import { ListTaskViewQuery, TaskState } from "./__generated__/ListTaskViewQuery.graphql";
|
||||||
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { Avatar } from "@/components/ui/avatar";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogClose,
|
||||||
|
DialogFooter,
|
||||||
|
} from "@/components/ui/dialog";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import {
|
||||||
|
CircleDashed,
|
||||||
|
Circle,
|
||||||
|
Plus,
|
||||||
|
Filter,
|
||||||
|
Search,
|
||||||
|
CornerDownRight,
|
||||||
|
Flame,
|
||||||
|
Building,
|
||||||
|
X,
|
||||||
|
ChevronDown,
|
||||||
|
User,
|
||||||
|
CheckCircle2,
|
||||||
|
} from "lucide-react";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { ListTaskViewOrganizationQuery } from "./__generated__/ListTaskViewOrganizationQuery.graphql";
|
||||||
|
|
||||||
|
// Function to format ISO8601 duration to human-readable format
|
||||||
|
const formatDuration = (isoDuration: string | null | undefined): string => {
|
||||||
|
if (!isoDuration || !isoDuration.startsWith("P")) {
|
||||||
|
return isoDuration || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const durationRegex =
|
||||||
|
/P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?/;
|
||||||
|
const matches = isoDuration.match(durationRegex);
|
||||||
|
|
||||||
|
if (!matches) return isoDuration;
|
||||||
|
|
||||||
|
const years = matches[1] ? parseInt(matches[1]) : 0;
|
||||||
|
const months = matches[2] ? parseInt(matches[2]) : 0;
|
||||||
|
const days = matches[3] ? parseInt(matches[3]) : 0;
|
||||||
|
const hours = matches[4] ? parseInt(matches[4]) : 0;
|
||||||
|
const minutes = matches[5] ? parseInt(matches[5]) : 0;
|
||||||
|
const seconds = matches[6] ? parseInt(matches[6]) : 0;
|
||||||
|
|
||||||
|
const parts = [];
|
||||||
|
if (years) parts.push(`${years} ${years === 1 ? "year" : "years"}`);
|
||||||
|
if (months) parts.push(`${months} ${months === 1 ? "month" : "months"}`);
|
||||||
|
if (days) parts.push(`${days} ${days === 1 ? "day" : "days"}`);
|
||||||
|
if (hours) parts.push(`${hours} ${hours === 1 ? "hour" : "hours"}`);
|
||||||
|
if (minutes)
|
||||||
|
parts.push(`${minutes} ${minutes === 1 ? "minute" : "minutes"}`);
|
||||||
|
if (seconds)
|
||||||
|
parts.push(`${seconds} ${seconds === 1 ? "second" : "seconds"}`);
|
||||||
|
|
||||||
|
return parts.length > 0 ? parts.join(", ") : "No duration";
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error parsing duration:", error);
|
||||||
|
return isoDuration;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define organization measures query
|
||||||
|
const organizationMeasuresQuery = graphql`
|
||||||
|
query ListTaskViewOrganizationMeasuresQuery($organizationId: ID!) {
|
||||||
|
organization: node(id: $organizationId) {
|
||||||
|
id
|
||||||
|
... on Organization {
|
||||||
|
measures(first: 100) @connection(key: "Organization__measures") {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
category
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Define the create task mutation
|
||||||
|
const createTaskMutation = graphql`
|
||||||
|
mutation ListTaskViewCreateTaskMutation(
|
||||||
|
$input: CreateTaskInput!
|
||||||
|
$connections: [ID!]!
|
||||||
|
) {
|
||||||
|
createTask(input: $input) {
|
||||||
|
taskEdge @prependEdge(connections: $connections) {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
state
|
||||||
|
timeEstimate
|
||||||
|
measure {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
assignedTo {
|
||||||
|
id
|
||||||
|
fullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Define the update task mutation
|
||||||
|
const updateTaskStateMutation = graphql`
|
||||||
|
mutation ListTaskViewUpdateTaskStateMutation(
|
||||||
|
$input: UpdateTaskInput!
|
||||||
|
) {
|
||||||
|
updateTask(input: $input) {
|
||||||
|
task {
|
||||||
|
id
|
||||||
|
state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const listTaskViewQuery = graphql`
|
||||||
|
query ListTaskViewQuery($organizationId: ID!) {
|
||||||
|
node(id: $organizationId) {
|
||||||
|
id
|
||||||
|
... on Organization {
|
||||||
|
name
|
||||||
|
tasks(first: 100) @connection(key: "ListTaskView_tasks") {
|
||||||
|
__id
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
state
|
||||||
|
timeEstimate
|
||||||
|
measure {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
assignedTo {
|
||||||
|
id
|
||||||
|
fullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Define organization members query
|
||||||
|
const organizationQuery = graphql`
|
||||||
|
query ListTaskViewOrganizationQuery($organizationId: ID!) {
|
||||||
|
organization: node(id: $organizationId) {
|
||||||
|
id
|
||||||
|
... on Organization {
|
||||||
|
peoples(first: 100, orderBy: { direction: ASC, field: FULL_NAME })
|
||||||
|
@connection(key: "ListTaskView_peoples") {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
fullName
|
||||||
|
primaryEmailAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface Badge {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: 'FIRE' | 'BANK' | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Task {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
state: string;
|
||||||
|
timeEstimate?: number | null;
|
||||||
|
assignedTo?: {
|
||||||
|
id: string;
|
||||||
|
fullName: string;
|
||||||
|
} | null;
|
||||||
|
parent?: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
} | null;
|
||||||
|
badges?: Badge[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function TaskCard({ task, onClick, onToggleState }: {
|
||||||
|
task: Task;
|
||||||
|
onClick?: (task: Task) => void;
|
||||||
|
onToggleState?: (taskId: string, newState: TaskState) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex justify-between items-center px-6 py-3 border-b border-gray-100 hover:bg-gray-50 cursor-pointer"
|
||||||
|
onClick={() => onClick && onClick(task)}
|
||||||
|
>
|
||||||
|
<div className="flex gap-4 items-center">
|
||||||
|
<div
|
||||||
|
className="flex items-center cursor-pointer"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (onToggleState) {
|
||||||
|
const newState = task.state === "TODO" ? "DONE" : "TODO";
|
||||||
|
onToggleState(task.id, newState as TaskState);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{task.state === "TODO" ? (
|
||||||
|
<CircleDashed className="w-5 h-5 text-green-500" />
|
||||||
|
) : task.state === "DONE" ? (
|
||||||
|
<CheckCircle2 className="w-5 h-5 text-gray-500" />
|
||||||
|
) : (
|
||||||
|
<Circle className="w-5 h-5 text-gray-300" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className={`text-sm font-medium ${task.state === "DONE" ? "text-gray-500 line-through" : "text-gray-900"}`}>
|
||||||
|
{task.name}
|
||||||
|
</span>
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className={`text-xs px-1.5 py-0.5 rounded-lg flex items-center gap-1
|
||||||
|
${task.state === "TODO"
|
||||||
|
? "bg-green-50 text-green-700 border-green-200"
|
||||||
|
: "bg-gray-50 text-gray-700 border-gray-200"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{task.state === "TODO" ? "To Do" : "Done"}
|
||||||
|
</Badge>
|
||||||
|
{task.timeEstimate && (
|
||||||
|
<span className="text-xs text-gray-500">
|
||||||
|
{formatDuration(task.timeEstimate.toString())}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{task.parent && (
|
||||||
|
<div className="flex items-center gap-1 text-sm text-gray-500">
|
||||||
|
<CornerDownRight className="w-3 h-3 text-gray-500" />
|
||||||
|
<span>{task.parent.name}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{task.badges && task.badges.map((badge) => (
|
||||||
|
<Badge
|
||||||
|
key={badge.id}
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs px-1.5 py-0.5 rounded-lg flex items-center gap-1 text-gray-600 border-gray-200/50"
|
||||||
|
>
|
||||||
|
{badge.type === "FIRE" ? (
|
||||||
|
<Flame className="w-3 h-3 text-gray-600" />
|
||||||
|
) : badge.type === "BANK" ? (
|
||||||
|
<Building className="w-3 h-3 text-gray-600" />
|
||||||
|
) : null}
|
||||||
|
{badge.name}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{task.assignedTo && (
|
||||||
|
<Avatar className="h-6 w-6 border border-white shadow-sm">
|
||||||
|
<div className="bg-green-100 h-full w-full rounded-full flex items-center justify-center text-[10px] font-medium text-green-800">
|
||||||
|
{task.assignedTo.fullName.split(' ').map((n: string) => n[0]).join('')}
|
||||||
|
</div>
|
||||||
|
</Avatar>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListTaskContent({
|
||||||
|
queryRef,
|
||||||
|
organizationQueryRef,
|
||||||
|
}: {
|
||||||
|
queryRef: PreloadedQuery<ListTaskViewQuery>;
|
||||||
|
organizationQueryRef: PreloadedQuery<ListTaskViewOrganizationQuery>;
|
||||||
|
}) {
|
||||||
|
const data = usePreloadedQuery<ListTaskViewQuery>(listTaskViewQuery, queryRef);
|
||||||
|
const organizationData = usePreloadedQuery<ListTaskViewOrganizationQuery>(
|
||||||
|
organizationQuery,
|
||||||
|
organizationQueryRef
|
||||||
|
);
|
||||||
|
|
||||||
|
const organization = data.node;
|
||||||
|
const [isNewTaskOpen, setIsNewTaskOpen] = useState(false);
|
||||||
|
|
||||||
|
// Get organization members
|
||||||
|
const members = organizationData.organization?.peoples?.edges.map(edge => edge.node) || [];
|
||||||
|
|
||||||
|
// Fetch measures
|
||||||
|
const environment = useRelayEnvironment();
|
||||||
|
const [measures, setMeasures] = useState<Array<{id: string, name: string, category: string, description?: string, state?: string}>>([]);
|
||||||
|
const [measuresLoading, setMeasuresLoading] = useState(false);
|
||||||
|
const [measureSearchQuery, setMeasureSearchQuery] = useState("");
|
||||||
|
|
||||||
|
// Task form state
|
||||||
|
const [taskTitle, setTaskTitle] = useState("");
|
||||||
|
const [taskDescription, setTaskDescription] = useState("");
|
||||||
|
const [taskStatus, setTaskStatus] = useState<"TODO" | "DONE">("TODO");
|
||||||
|
const [assignee, setAssignee] = useState<{id: string, fullName: string} | null>(null);
|
||||||
|
const [measureId, setMeasureId] = useState<string | null>(null);
|
||||||
|
const [selectedMeasure, setSelectedMeasure] = useState<{id: string, name: string} | null>(null);
|
||||||
|
const [timeEstimate, setTimeEstimate] = useState<number | null>(null);
|
||||||
|
const [timeUnit, setTimeUnit] = useState<"minutes" | "hours" | "days" | "weeks">("hours");
|
||||||
|
|
||||||
|
// Create task mutation
|
||||||
|
const [createTask, isCreatingTask] = useMutation(createTaskMutation);
|
||||||
|
|
||||||
|
// Update task state mutation
|
||||||
|
const [updateTaskState] = useMutation(updateTaskStateMutation);
|
||||||
|
|
||||||
|
// Fetch measures from the organization
|
||||||
|
useEffect(() => {
|
||||||
|
if (organization?.id) {
|
||||||
|
setMeasuresLoading(true);
|
||||||
|
fetchQuery(
|
||||||
|
environment,
|
||||||
|
organizationMeasuresQuery,
|
||||||
|
{ organizationId: organization.id }
|
||||||
|
).subscribe({
|
||||||
|
next: (data: any) => {
|
||||||
|
if (data.organization?.measures?.edges) {
|
||||||
|
const measuresList = data.organization.measures.edges.map((edge: any) => ({
|
||||||
|
id: edge.node.id,
|
||||||
|
name: edge.node.name,
|
||||||
|
category: edge.node.category,
|
||||||
|
description: edge.node.description,
|
||||||
|
state: edge.node.state
|
||||||
|
}));
|
||||||
|
setMeasures(measuresList);
|
||||||
|
}
|
||||||
|
setMeasuresLoading(false);
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
setMeasuresLoading(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [environment, organization?.id]);
|
||||||
|
|
||||||
|
// Filter measures based on search query
|
||||||
|
const filteredMeasures = measures.filter(measure =>
|
||||||
|
measure.name.toLowerCase().includes(measureSearchQuery.toLowerCase()) ||
|
||||||
|
(measure.description && measure.description.toLowerCase().includes(measureSearchQuery.toLowerCase()))
|
||||||
|
);
|
||||||
|
|
||||||
|
const allTasks = data.node?.tasks?.edges.map((edge) => ({
|
||||||
|
...edge.node,
|
||||||
|
badges: [
|
||||||
|
{ id: "1", name: "Policy violation", type: "FIRE" },
|
||||||
|
{ id: "2", name: "SOC2", type: "BANK" },
|
||||||
|
],
|
||||||
|
parent: edge.node.measure ? { id: edge.node.measure.id, name: edge.node.measure.name } : null,
|
||||||
|
})) || [];
|
||||||
|
|
||||||
|
const todoTasks = allTasks.filter(task => task.state === "TODO");
|
||||||
|
const doneTasks = allTasks.filter(task => task.state === "DONE");
|
||||||
|
|
||||||
|
const handleTaskClick = (task: Task) => {
|
||||||
|
console.log("Task clicked:", task);
|
||||||
|
// Navigate to task detail page
|
||||||
|
// window.location.href = `/organizations/${organizationId}/tasks/${task.id}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to convert timeEstimate to ISO8601 duration
|
||||||
|
const convertToISODuration = (value: number | null, unit: string): string | null => {
|
||||||
|
if (value === null || value <= 0) return null;
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case "minutes":
|
||||||
|
return `PT${value}M`;
|
||||||
|
case "hours":
|
||||||
|
return `PT${value}H`;
|
||||||
|
case "days":
|
||||||
|
return `P${value}D`;
|
||||||
|
case "weeks":
|
||||||
|
return `P${value * 7}D`;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateTask = () => {
|
||||||
|
if (!taskTitle.trim()) return;
|
||||||
|
|
||||||
|
// Convert timeEstimate to ISO8601 duration
|
||||||
|
const formattedTimeEstimate = convertToISODuration(timeEstimate, timeUnit);
|
||||||
|
|
||||||
|
createTask({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
name: taskTitle,
|
||||||
|
description: taskDescription,
|
||||||
|
organizationId: organization?.id || "",
|
||||||
|
measureId: selectedMeasure?.id || null,
|
||||||
|
assignedToId: assignee?.id,
|
||||||
|
timeEstimate: formattedTimeEstimate,
|
||||||
|
},
|
||||||
|
connections: [data.node?.tasks?.__id || ""],
|
||||||
|
},
|
||||||
|
onCompleted: () => {
|
||||||
|
setIsNewTaskOpen(false);
|
||||||
|
resetTaskForm();
|
||||||
|
},
|
||||||
|
onError: error => {
|
||||||
|
console.error("Error creating task:", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetTaskForm = () => {
|
||||||
|
setTaskTitle("");
|
||||||
|
setTaskDescription("");
|
||||||
|
setTaskStatus("TODO");
|
||||||
|
setAssignee(null);
|
||||||
|
setSelectedMeasure(null);
|
||||||
|
setMeasureId(null);
|
||||||
|
setTimeEstimate(null);
|
||||||
|
setTimeUnit("hours");
|
||||||
|
setMeasureSearchQuery("");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get initials from name
|
||||||
|
const getInitials = (name: string) => {
|
||||||
|
return name.split(' ').map(n => n[0]).join('');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle toggling task state
|
||||||
|
const handleToggleTaskState = (taskId: string, newState: TaskState) => {
|
||||||
|
updateTaskState({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
taskId: taskId,
|
||||||
|
state: newState
|
||||||
|
}
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
updateTask: {
|
||||||
|
task: {
|
||||||
|
id: taskId,
|
||||||
|
state: newState,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageTemplate
|
||||||
|
title="Tasks"
|
||||||
|
description="Track your assigned compliance tasks and keep progress on track."
|
||||||
|
actions={
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
className="bg-gray-900 text-white hover:bg-gray-800 gap-1.5"
|
||||||
|
onClick={() => setIsNewTaskOpen(true)}
|
||||||
|
>
|
||||||
|
<Plus className="w-4 h-4" />
|
||||||
|
New task
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="border border-gray-100 rounded-xl p-0 overflow-hidden">
|
||||||
|
<div className="px-6 py-4 border-b border-gray-100">
|
||||||
|
<Tabs defaultValue="todo" className="w-full">
|
||||||
|
<div className="flex justify-between items-center w-full mb-6">
|
||||||
|
<TabsList className="w-full">
|
||||||
|
<TabsTrigger value="todo" className="border-b-2 border-transparent data-[state=active]:border-gray-900">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<CircleDashed className="w-4 h-4 text-green-500" />
|
||||||
|
<span>To Do</span>
|
||||||
|
<div className="flex items-center justify-center bg-green-100 rounded-full h-6 w-6 text-xs text-green-800">
|
||||||
|
{todoTasks.length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="done" className="border-b-2 border-transparent data-[state=active]:border-gray-900">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Circle className="w-4 h-4 text-gray-500" />
|
||||||
|
<span>Done</span>
|
||||||
|
<div className="flex items-center justify-center bg-gray-100 rounded-full h-6 w-6 text-xs text-gray-800">
|
||||||
|
{doneTasks.length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="all" className="border-b-2 border-transparent data-[state=active]:border-gray-900">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span>All</span>
|
||||||
|
<div className="flex items-center justify-center bg-gray-100 rounded-full h-6 w-6 text-xs">
|
||||||
|
{allTasks.length}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TabsContent value="todo">
|
||||||
|
{todoTasks.length > 0 ? (
|
||||||
|
todoTasks.map((task) => (
|
||||||
|
<TaskCard
|
||||||
|
key={task.id}
|
||||||
|
task={task}
|
||||||
|
onClick={handleTaskClick}
|
||||||
|
onToggleState={handleToggleTaskState}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="p-4 text-center text-gray-500">
|
||||||
|
No todo tasks found. Create a new task to get started.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="done">
|
||||||
|
{doneTasks.length > 0 ? (
|
||||||
|
doneTasks.map((task) => (
|
||||||
|
<TaskCard
|
||||||
|
key={task.id}
|
||||||
|
task={task}
|
||||||
|
onClick={handleTaskClick}
|
||||||
|
onToggleState={handleToggleTaskState}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="p-4 text-center text-gray-500">
|
||||||
|
No completed tasks found.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="all">
|
||||||
|
{allTasks.length > 0 ? (
|
||||||
|
allTasks.map((task) => (
|
||||||
|
<TaskCard
|
||||||
|
key={task.id}
|
||||||
|
task={task}
|
||||||
|
onClick={handleTaskClick}
|
||||||
|
onToggleState={handleToggleTaskState}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="p-4 text-center text-gray-500">
|
||||||
|
No tasks found. Create a new task to get started.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* New Task Modal */}
|
||||||
|
<Dialog open={isNewTaskOpen} onOpenChange={setIsNewTaskOpen}>
|
||||||
|
<DialogContent className="sm:max-w-[1080px] p-0 rounded-lg overflow-hidden border border-gray-200">
|
||||||
|
{/* Modal Header */}
|
||||||
|
<div className="flex justify-between items-center px-6 py-4 border-b border-[rgba(2,42,2,0.08)]">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="text-sm text-gray-500">List of your assets</div>
|
||||||
|
<div className="text-gray-500">
|
||||||
|
<CornerDownRight className="w-3 h-3" />
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-medium">New task</div>
|
||||||
|
</div>
|
||||||
|
<DialogClose className="rounded-full w-8 h-8 flex items-center justify-center hover:bg-gray-100"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Task Form - Two Column Layout */}
|
||||||
|
<div className="flex">
|
||||||
|
{/* Left Column - Task Details */}
|
||||||
|
<div className="flex-1 border-r border-[rgba(2,42,2,0.08)] p-6">
|
||||||
|
<Input
|
||||||
|
placeholder="Task title"
|
||||||
|
className="text-2xl font-semibold border-none px-0 mb-4 w-full"
|
||||||
|
value={taskTitle}
|
||||||
|
onChange={(e) => setTaskTitle(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Textarea
|
||||||
|
placeholder="Add description..."
|
||||||
|
className="resize-none border-none px-0 text-base w-full min-h-[400px]"
|
||||||
|
value={taskDescription}
|
||||||
|
onChange={(e) => setTaskDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Right Column - Properties */}
|
||||||
|
<div className="w-[400px] p-6">
|
||||||
|
<h3 className="text-base font-medium text-gray-900 mb-4">Properties</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Status */}
|
||||||
|
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
|
||||||
|
<Label className="text-sm font-medium text-gray-500">Status</Label>
|
||||||
|
<div className="bg-[rgba(0,39,0,0.05)] px-[10px] py-[6px] rounded-lg flex items-center gap-1.5">
|
||||||
|
<img
|
||||||
|
src="/images/radio-unchecked.svg"
|
||||||
|
alt="Radio"
|
||||||
|
className="w-4 h-4"
|
||||||
|
/>
|
||||||
|
<span className="text-sm font-medium">To do</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Assignee */}
|
||||||
|
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
|
||||||
|
<Label className="text-sm font-medium text-gray-500">Assignee</Label>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<div className="bg-[rgba(0,39,0,0.05)] px-[10px] py-[6px] rounded-lg flex items-center gap-1.5 cursor-pointer">
|
||||||
|
{assignee ? (
|
||||||
|
<>
|
||||||
|
<Avatar className="h-4 w-4">
|
||||||
|
<div className="bg-blue-100 h-full w-full rounded-full flex items-center justify-center text-[7px] font-medium text-blue-800">
|
||||||
|
{getInitials(assignee.fullName)}
|
||||||
|
</div>
|
||||||
|
</Avatar>
|
||||||
|
<span className="text-sm font-medium">{assignee.fullName}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<User className="h-4 w-4 text-gray-500" />
|
||||||
|
<span className="text-sm font-medium">Unassigned</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<ChevronDown className="h-3 w-3 text-gray-500 ml-1" />
|
||||||
|
</div>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" className="w-[220px] max-h-[300px] overflow-y-auto">
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="flex items-center gap-2 cursor-pointer"
|
||||||
|
onClick={() => setAssignee(null)}
|
||||||
|
>
|
||||||
|
<User className="h-4 w-4 text-gray-500" />
|
||||||
|
<span>Unassigned</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
|
||||||
|
{members.map(member => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
key={member.id}
|
||||||
|
className="flex items-center gap-2 cursor-pointer"
|
||||||
|
onClick={() => setAssignee({id: member.id, fullName: member.fullName})}
|
||||||
|
>
|
||||||
|
<Avatar className="h-4 w-4">
|
||||||
|
<div className="bg-blue-100 h-full w-full rounded-full flex items-center justify-center text-[7px] font-medium text-blue-800">
|
||||||
|
{getInitials(member.fullName)}
|
||||||
|
</div>
|
||||||
|
</Avatar>
|
||||||
|
<span>{member.fullName}</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Measure */}
|
||||||
|
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
|
||||||
|
<Label className="text-sm font-medium text-gray-500">Measure</Label>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<div className="bg-[rgba(0,39,0,0.05)] px-[10px] py-[6px] rounded-lg flex items-center gap-1.5 cursor-pointer">
|
||||||
|
{selectedMeasure ? (
|
||||||
|
<span className="text-sm font-medium">{selectedMeasure.name}</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-sm font-medium">No measure</span>
|
||||||
|
)}
|
||||||
|
<ChevronDown className="h-3 w-3 text-gray-500 ml-1" />
|
||||||
|
</div>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" className="w-[320px] max-h-[300px] overflow-y-auto">
|
||||||
|
<div className="p-2">
|
||||||
|
<div className="relative mb-2">
|
||||||
|
<Search className="absolute left-2 top-2.5 h-4 w-4 text-gray-500" />
|
||||||
|
<Input
|
||||||
|
placeholder="Search measures..."
|
||||||
|
value={measureSearchQuery}
|
||||||
|
onChange={(e) => setMeasureSearchQuery(e.target.value)}
|
||||||
|
className="pl-8"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="flex items-center gap-2 cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedMeasure(null);
|
||||||
|
setMeasureId(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>No measure</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
|
||||||
|
{measuresLoading ? (
|
||||||
|
<div className="p-3 text-center text-sm text-gray-500">
|
||||||
|
Loading measures...
|
||||||
|
</div>
|
||||||
|
) : filteredMeasures.length > 0 ? (
|
||||||
|
filteredMeasures.map(measure => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
key={measure.id}
|
||||||
|
className="flex items-start gap-2 cursor-pointer py-2"
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedMeasure({id: measure.id, name: measure.name});
|
||||||
|
setMeasureId(measure.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="font-medium">{measure.name}</span>
|
||||||
|
{measure.category && (
|
||||||
|
<span className="text-xs text-gray-500">{measure.category}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="p-3 text-center text-sm text-gray-500">
|
||||||
|
No measures found
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Time estimate */}
|
||||||
|
<div className="flex justify-between items-center border-b border-[rgba(2,42,2,0.08)] py-3">
|
||||||
|
<Label className="text-sm font-medium text-gray-500">Time estimate</Label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
{timeEstimate === null ? (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-8 px-2"
|
||||||
|
onClick={() => setTimeEstimate(0)}
|
||||||
|
>
|
||||||
|
<Plus className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
value={timeEstimate}
|
||||||
|
onChange={(e) => setTimeEstimate(parseInt(e.target.value) || 0)}
|
||||||
|
className="w-16 h-8 text-sm"
|
||||||
|
/>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="h-8 flex items-center gap-1"
|
||||||
|
>
|
||||||
|
<span>{timeUnit}</span>
|
||||||
|
<ChevronDown className="h-3 w-3" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end">
|
||||||
|
<DropdownMenuItem onClick={() => setTimeUnit("minutes")}>
|
||||||
|
minutes
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => setTimeUnit("hours")}>
|
||||||
|
hours
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => setTimeUnit("days")}>
|
||||||
|
days
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem onClick={() => setTimeUnit("weeks")}>
|
||||||
|
weeks
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-8 p-0"
|
||||||
|
onClick={() => setTimeEstimate(null)}
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Modal Footer */}
|
||||||
|
<div className="flex justify-between items-center px-6 py-4 border-t border-[rgba(2,42,2,0.08)]">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 flex items-center gap-1.5 border-[rgba(2,42,2,0.08)]"
|
||||||
|
>
|
||||||
|
<img src="/images/attachment.svg" alt="Attachment" className="w-4 h-4" />
|
||||||
|
Upload evidence
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className="h-8 border-[rgba(2,42,2,0.08)]"
|
||||||
|
onClick={() => setIsNewTaskOpen(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="h-8 bg-gray-900 text-white"
|
||||||
|
onClick={handleCreateTask}
|
||||||
|
disabled={!taskTitle.trim()}
|
||||||
|
>
|
||||||
|
Create task
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
</PageTemplate>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ListTaskView() {
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const [queryRef, loadQuery] =
|
||||||
|
useQueryLoader<ListTaskViewQuery>(listTaskViewQuery);
|
||||||
|
const [organizationQueryRef, loadOrganizationQuery] =
|
||||||
|
useQueryLoader<ListTaskViewOrganizationQuery>(organizationQuery);
|
||||||
|
|
||||||
|
const { organizationId } = useParams();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadQuery({ organizationId: organizationId! });
|
||||||
|
loadOrganizationQuery({ organizationId: organizationId! });
|
||||||
|
}, [loadQuery, loadOrganizationQuery, organizationId]);
|
||||||
|
|
||||||
|
if (!queryRef || !organizationQueryRef) {
|
||||||
|
return <ListTaskViewSkeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<ListTaskViewSkeleton />}>
|
||||||
|
<ListTaskContent queryRef={queryRef} organizationQueryRef={organizationQueryRef} />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
238
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewCreateTaskMutation.graphql.ts
generated
Normal file
238
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewCreateTaskMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<84a35602a155b0f1fa8504cf32c10932>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type TaskState = "DONE" | "TODO";
|
||||||
|
export type CreateTaskInput = {
|
||||||
|
assignedToId?: string | null | undefined;
|
||||||
|
description: string;
|
||||||
|
measureId?: string | null | undefined;
|
||||||
|
name: string;
|
||||||
|
organizationId: string;
|
||||||
|
timeEstimate?: any | null | undefined;
|
||||||
|
};
|
||||||
|
export type ListTaskViewCreateTaskMutation$variables = {
|
||||||
|
connections: ReadonlyArray<string>;
|
||||||
|
input: CreateTaskInput;
|
||||||
|
};
|
||||||
|
export type ListTaskViewCreateTaskMutation$data = {
|
||||||
|
readonly createTask: {
|
||||||
|
readonly taskEdge: {
|
||||||
|
readonly node: {
|
||||||
|
readonly assignedTo: {
|
||||||
|
readonly fullName: string;
|
||||||
|
readonly id: string;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly description: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly measure: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly name: string;
|
||||||
|
readonly state: TaskState;
|
||||||
|
readonly timeEstimate: any | null | undefined;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ListTaskViewCreateTaskMutation = {
|
||||||
|
response: ListTaskViewCreateTaskMutation$data;
|
||||||
|
variables: ListTaskViewCreateTaskMutation$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = {
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "connections"
|
||||||
|
},
|
||||||
|
v1 = {
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "input"
|
||||||
|
},
|
||||||
|
v2 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "input",
|
||||||
|
"variableName": "input"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v3 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v4 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v5 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "TaskEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "taskEdge",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Task",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
(v4/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "description",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "state",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "timeEstimate",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Measure",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "measure",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
(v4/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "People",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "assignedTo",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "fullName",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
(v0/*: any*/),
|
||||||
|
(v1/*: any*/)
|
||||||
|
],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ListTaskViewCreateTaskMutation",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v2/*: any*/),
|
||||||
|
"concreteType": "CreateTaskPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "createTask",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v5/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Mutation",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
(v1/*: any*/),
|
||||||
|
(v0/*: any*/)
|
||||||
|
],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ListTaskViewCreateTaskMutation",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v2/*: any*/),
|
||||||
|
"concreteType": "CreateTaskPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "createTask",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v5/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"filters": null,
|
||||||
|
"handle": "prependEdge",
|
||||||
|
"key": "",
|
||||||
|
"kind": "LinkedHandle",
|
||||||
|
"name": "taskEdge",
|
||||||
|
"handleArgs": [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "connections",
|
||||||
|
"variableName": "connections"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "7b9680f637411402ff51239a43b44a14",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "ListTaskViewCreateTaskMutation",
|
||||||
|
"operationKind": "mutation",
|
||||||
|
"text": "mutation ListTaskViewCreateTaskMutation(\n $input: CreateTaskInput!\n) {\n createTask(input: $input) {\n taskEdge {\n node {\n id\n name\n description\n state\n timeEstimate\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n }\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "43ccaf49d31ec84dcf3b6b3f2e3a851c";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<5d866d20a606b1fb34d64ad47aa76f78>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type MeasureState = "IMPLEMENTED" | "IN_PROGRESS" | "NOT_APPLICABLE" | "NOT_STARTED";
|
||||||
|
export type ListTaskViewOrganizationMeasuresQuery$variables = {
|
||||||
|
organizationId: string;
|
||||||
|
};
|
||||||
|
export type ListTaskViewOrganizationMeasuresQuery$data = {
|
||||||
|
readonly organization: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly measures?: {
|
||||||
|
readonly edges: ReadonlyArray<{
|
||||||
|
readonly node: {
|
||||||
|
readonly category: string;
|
||||||
|
readonly description: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly state: MeasureState;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ListTaskViewOrganizationMeasuresQuery = {
|
||||||
|
response: ListTaskViewOrganizationMeasuresQuery$data;
|
||||||
|
variables: ListTaskViewOrganizationMeasuresQuery$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v1 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "id",
|
||||||
|
"variableName": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v2 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v3 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "__typename",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v4 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "MeasureEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Measure",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "description",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "category",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "state",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
(v3/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "cursor",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "PageInfo",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "pageInfo",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "endCursor",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "hasNextPage",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v5 = [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "first",
|
||||||
|
"value": 100
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ListTaskViewOrganizationMeasuresQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "organization",
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "measures",
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "MeasureConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "__Organization__measures_connection",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v4/*: any*/),
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Organization",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ListTaskViewOrganizationMeasuresQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "organization",
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v5/*: any*/),
|
||||||
|
"concreteType": "MeasureConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "measures",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v4/*: any*/),
|
||||||
|
"storageKey": "measures(first:100)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v5/*: any*/),
|
||||||
|
"filters": null,
|
||||||
|
"handle": "connection",
|
||||||
|
"key": "Organization__measures",
|
||||||
|
"kind": "LinkedHandle",
|
||||||
|
"name": "measures"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Organization",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "1986791d30c729854184fc15725ff5f0",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {
|
||||||
|
"connection": [
|
||||||
|
{
|
||||||
|
"count": null,
|
||||||
|
"cursor": null,
|
||||||
|
"direction": "forward",
|
||||||
|
"path": [
|
||||||
|
"organization",
|
||||||
|
"measures"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "ListTaskViewOrganizationMeasuresQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query ListTaskViewOrganizationMeasuresQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n measures(first: 100) {\n edges {\n node {\n id\n name\n description\n category\n state\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "3a4008ec2a42d13418f83e9ddd460b34";
|
||||||
|
|
||||||
|
export default node;
|
||||||
267
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewOrganizationQuery.graphql.ts
generated
Normal file
267
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewOrganizationQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<c922e0dcd99fb4bc9d1d26954781b945>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type ListTaskViewOrganizationQuery$variables = {
|
||||||
|
organizationId: string;
|
||||||
|
};
|
||||||
|
export type ListTaskViewOrganizationQuery$data = {
|
||||||
|
readonly organization: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly peoples?: {
|
||||||
|
readonly edges: ReadonlyArray<{
|
||||||
|
readonly node: {
|
||||||
|
readonly fullName: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly primaryEmailAddress: string;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ListTaskViewOrganizationQuery = {
|
||||||
|
response: ListTaskViewOrganizationQuery$data;
|
||||||
|
variables: ListTaskViewOrganizationQuery$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v1 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "id",
|
||||||
|
"variableName": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v2 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v3 = {
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "orderBy",
|
||||||
|
"value": {
|
||||||
|
"direction": "ASC",
|
||||||
|
"field": "FULL_NAME"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
v4 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "__typename",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v5 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "PeopleEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "People",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "fullName",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "primaryEmailAddress",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
(v4/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "cursor",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "PageInfo",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "pageInfo",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "endCursor",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "hasNextPage",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v6 = [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "first",
|
||||||
|
"value": 100
|
||||||
|
},
|
||||||
|
(v3/*: any*/)
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ListTaskViewOrganizationQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "organization",
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "peoples",
|
||||||
|
"args": [
|
||||||
|
(v3/*: any*/)
|
||||||
|
],
|
||||||
|
"concreteType": "PeopleConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "__ListTaskView_peoples_connection",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v5/*: any*/),
|
||||||
|
"storageKey": "__ListTaskView_peoples_connection(orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Organization",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ListTaskViewOrganizationQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": "organization",
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v4/*: any*/),
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v6/*: any*/),
|
||||||
|
"concreteType": "PeopleConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "peoples",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v5/*: any*/),
|
||||||
|
"storageKey": "peoples(first:100,orderBy:{\"direction\":\"ASC\",\"field\":\"FULL_NAME\"})"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v6/*: any*/),
|
||||||
|
"filters": [
|
||||||
|
"orderBy"
|
||||||
|
],
|
||||||
|
"handle": "connection",
|
||||||
|
"key": "ListTaskView_peoples",
|
||||||
|
"kind": "LinkedHandle",
|
||||||
|
"name": "peoples"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Organization",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "a2ecca8e88fa80fc9828ddc2a04d18ac",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {
|
||||||
|
"connection": [
|
||||||
|
{
|
||||||
|
"count": null,
|
||||||
|
"cursor": null,
|
||||||
|
"direction": "forward",
|
||||||
|
"path": [
|
||||||
|
"organization",
|
||||||
|
"peoples"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "ListTaskViewOrganizationQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query ListTaskViewOrganizationQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n peoples(first: 100, orderBy: {direction: ASC, field: FULL_NAME}) {\n edges {\n node {\n id\n fullName\n primaryEmailAddress\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "736b443f4010e86687954adcaed6f3ab";
|
||||||
|
|
||||||
|
export default node;
|
||||||
328
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewQuery.graphql.ts
generated
Normal file
328
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<7732676a00f7ed0f6817555b68540aca>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type TaskState = "DONE" | "TODO";
|
||||||
|
export type ListTaskViewQuery$variables = {
|
||||||
|
organizationId: string;
|
||||||
|
};
|
||||||
|
export type ListTaskViewQuery$data = {
|
||||||
|
readonly node: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly name?: string;
|
||||||
|
readonly tasks?: {
|
||||||
|
readonly __id: string;
|
||||||
|
readonly edges: ReadonlyArray<{
|
||||||
|
readonly node: {
|
||||||
|
readonly assignedTo: {
|
||||||
|
readonly fullName: string;
|
||||||
|
readonly id: string;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly description: string;
|
||||||
|
readonly id: string;
|
||||||
|
readonly measure: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
} | null | undefined;
|
||||||
|
readonly name: string;
|
||||||
|
readonly state: TaskState;
|
||||||
|
readonly timeEstimate: any | null | undefined;
|
||||||
|
};
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ListTaskViewQuery = {
|
||||||
|
response: ListTaskViewQuery$data;
|
||||||
|
variables: ListTaskViewQuery$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v1 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "id",
|
||||||
|
"variableName": "organizationId"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v2 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v3 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v4 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "__typename",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
v5 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "TaskEdge",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "edges",
|
||||||
|
"plural": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Task",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
(v3/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "description",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "state",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "timeEstimate",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Measure",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "measure",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
(v3/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "People",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "assignedTo",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "fullName",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
(v4/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "cursor",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "PageInfo",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "pageInfo",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "endCursor",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "hasNextPage",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "ClientExtension",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "__id",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v6 = [
|
||||||
|
{
|
||||||
|
"kind": "Literal",
|
||||||
|
"name": "first",
|
||||||
|
"value": 100
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ListTaskViewQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": "tasks",
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "TaskConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "__ListTaskView_tasks_connection",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v5/*: any*/),
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Organization",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ListTaskViewQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v1/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v4/*: any*/),
|
||||||
|
(v2/*: any*/),
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v6/*: any*/),
|
||||||
|
"concreteType": "TaskConnection",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "tasks",
|
||||||
|
"plural": false,
|
||||||
|
"selections": (v5/*: any*/),
|
||||||
|
"storageKey": "tasks(first:100)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v6/*: any*/),
|
||||||
|
"filters": null,
|
||||||
|
"handle": "connection",
|
||||||
|
"key": "ListTaskView_tasks",
|
||||||
|
"kind": "LinkedHandle",
|
||||||
|
"name": "tasks"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Organization",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "52b577b08c305249855293949d6e2339",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {
|
||||||
|
"connection": [
|
||||||
|
{
|
||||||
|
"count": null,
|
||||||
|
"cursor": null,
|
||||||
|
"direction": "forward",
|
||||||
|
"path": [
|
||||||
|
"node",
|
||||||
|
"tasks"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"name": "ListTaskViewQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query ListTaskViewQuery(\n $organizationId: ID!\n) {\n node(id: $organizationId) {\n __typename\n id\n ... on Organization {\n name\n tasks(first: 100) {\n edges {\n node {\n id\n name\n description\n state\n timeEstimate\n measure {\n id\n name\n }\n assignedTo {\n id\n fullName\n }\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "5ca091444c547744068f2b2a83cb31df";
|
||||||
|
|
||||||
|
export default node;
|
||||||
118
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewUpdateTaskStateMutation.graphql.ts
generated
Normal file
118
apps/console/src/pages/organizations/tasks/__generated__/ListTaskViewUpdateTaskStateMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<7098e326d01cc6831f293726096a7275>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type TaskState = "DONE" | "TODO";
|
||||||
|
export type UpdateTaskInput = {
|
||||||
|
description?: string | null | undefined;
|
||||||
|
name?: string | null | undefined;
|
||||||
|
state?: TaskState | null | undefined;
|
||||||
|
taskId: string;
|
||||||
|
timeEstimate?: any | null | undefined;
|
||||||
|
};
|
||||||
|
export type ListTaskViewUpdateTaskStateMutation$variables = {
|
||||||
|
input: UpdateTaskInput;
|
||||||
|
};
|
||||||
|
export type ListTaskViewUpdateTaskStateMutation$data = {
|
||||||
|
readonly updateTask: {
|
||||||
|
readonly task: {
|
||||||
|
readonly id: string;
|
||||||
|
readonly state: TaskState;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export type ListTaskViewUpdateTaskStateMutation = {
|
||||||
|
response: ListTaskViewUpdateTaskStateMutation$data;
|
||||||
|
variables: ListTaskViewUpdateTaskStateMutation$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = [
|
||||||
|
{
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "input"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v1 = [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "input",
|
||||||
|
"variableName": "input"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"concreteType": "UpdateTaskPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "updateTask",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"concreteType": "Task",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "task",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "state",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "ListTaskViewUpdateTaskStateMutation",
|
||||||
|
"selections": (v1/*: any*/),
|
||||||
|
"type": "Mutation",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": (v0/*: any*/),
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "ListTaskViewUpdateTaskStateMutation",
|
||||||
|
"selections": (v1/*: any*/)
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "ddeeb9b6aa991efa6e305491ef360537",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "ListTaskViewUpdateTaskStateMutation",
|
||||||
|
"operationKind": "mutation",
|
||||||
|
"text": "mutation ListTaskViewUpdateTaskStateMutation(\n $input: UpdateTaskInput!\n) {\n updateTask(input: $input) {\n task {\n id\n state\n }\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "46d32aeba7c467fd48291f43baaf0b6a";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -30,7 +30,6 @@ import (
|
|||||||
type (
|
type (
|
||||||
Measure struct {
|
Measure struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
TenantID gid.TenantID `db:"tenant_id"`
|
|
||||||
OrganizationID gid.GID `db:"organization_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
Category string `db:"category"`
|
Category string `db:"category"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
@@ -82,7 +81,6 @@ WITH msrs AS (
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
tenant_id,
|
|
||||||
organization_id,
|
organization_id,
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
@@ -146,7 +144,6 @@ WITH mtgtns AS (
|
|||||||
)
|
)
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
tenant_id,
|
|
||||||
organization_id,
|
organization_id,
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
@@ -191,7 +188,6 @@ func (m *Measures) LoadByOrganizationID(
|
|||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
tenant_id,
|
|
||||||
organization_id,
|
organization_id,
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
@@ -237,7 +233,6 @@ func (m *Measure) LoadByID(
|
|||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
tenant_id,
|
|
||||||
organization_id,
|
organization_id,
|
||||||
category,
|
category,
|
||||||
name,
|
name,
|
||||||
@@ -311,7 +306,6 @@ ON CONFLICT (organization_id, reference_id) DO UPDATE SET
|
|||||||
category = @category,
|
category = @category,
|
||||||
updated_at = @updated_at
|
updated_at = @updated_at
|
||||||
RETURNING
|
RETURNING
|
||||||
tenant_id,
|
|
||||||
id,
|
id,
|
||||||
organization_id,
|
organization_id,
|
||||||
category,
|
category,
|
||||||
8
pkg/coredata/migrations/20250505T171400Z.sql
Normal file
8
pkg/coredata/migrations/20250505T171400Z.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
ALTER TABLE tasks ADD COLUMN organization_id TEXT REFERENCES organizations(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
UPDATE tasks
|
||||||
|
SET organization_id = m.organization_id::text
|
||||||
|
FROM measures m
|
||||||
|
WHERE tasks.measure_id = m.id;
|
||||||
|
|
||||||
|
ALTER TABLE tasks ALTER COLUMN organization_id SET NOT NULL;
|
||||||
@@ -166,8 +166,9 @@ WHERE %s
|
|||||||
`
|
`
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
||||||
|
|
||||||
args := pgx.NamedArgs{"organization_id": organizationID}
|
args := pgx.StrictNamedArgs{"organization_id": organizationID}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
maps.Copy(args, cursor.SQLArguments())
|
||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
rows, err := conn.Query(ctx, q, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ import (
|
|||||||
type (
|
type (
|
||||||
Task struct {
|
Task struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
MeasureID gid.GID `db:"measure_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
|
MeasureID *gid.GID `db:"measure_id"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
Description string `db:"description"`
|
Description string `db:"description"`
|
||||||
State TaskState `db:"state"`
|
State TaskState `db:"state"`
|
||||||
@@ -62,6 +63,7 @@ func (c *Task) LoadByID(
|
|||||||
q := `
|
q := `
|
||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
|
organization_id,
|
||||||
measure_id,
|
measure_id,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
@@ -109,6 +111,7 @@ INSERT INTO
|
|||||||
tasks (
|
tasks (
|
||||||
tenant_id,
|
tenant_id,
|
||||||
id,
|
id,
|
||||||
|
organization_id,
|
||||||
measure_id,
|
measure_id,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
@@ -122,6 +125,7 @@ INSERT INTO
|
|||||||
VALUES (
|
VALUES (
|
||||||
@tenant_id,
|
@tenant_id,
|
||||||
@task_id,
|
@task_id,
|
||||||
|
@organization_id,
|
||||||
@measure_id,
|
@measure_id,
|
||||||
@name,
|
@name,
|
||||||
@description,
|
@description,
|
||||||
@@ -137,6 +141,7 @@ VALUES (
|
|||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"tenant_id": scope.GetTenantID(),
|
"tenant_id": scope.GetTenantID(),
|
||||||
"task_id": c.ID,
|
"task_id": c.ID,
|
||||||
|
"organization_id": c.OrganizationID,
|
||||||
"measure_id": c.MeasureID,
|
"measure_id": c.MeasureID,
|
||||||
"name": c.Name,
|
"name": c.Name,
|
||||||
"description": c.Description,
|
"description": c.Description,
|
||||||
@@ -161,6 +166,7 @@ INSERT INTO
|
|||||||
tasks (
|
tasks (
|
||||||
tenant_id,
|
tenant_id,
|
||||||
id,
|
id,
|
||||||
|
organization_id,
|
||||||
measure_id,
|
measure_id,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
@@ -174,6 +180,7 @@ INSERT INTO
|
|||||||
VALUES (
|
VALUES (
|
||||||
@tenant_id,
|
@tenant_id,
|
||||||
@task_id,
|
@task_id,
|
||||||
|
@organization_id,
|
||||||
@measure_id,
|
@measure_id,
|
||||||
@name,
|
@name,
|
||||||
@description,
|
@description,
|
||||||
@@ -190,6 +197,7 @@ ON CONFLICT (measure_id, reference_id) DO UPDATE SET
|
|||||||
updated_at = @updated_at
|
updated_at = @updated_at
|
||||||
RETURNING
|
RETURNING
|
||||||
id,
|
id,
|
||||||
|
organization_id,
|
||||||
measure_id,
|
measure_id,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
@@ -204,6 +212,7 @@ RETURNING
|
|||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"tenant_id": scope.GetTenantID(),
|
"tenant_id": scope.GetTenantID(),
|
||||||
"task_id": c.ID,
|
"task_id": c.ID,
|
||||||
|
"organization_id": c.OrganizationID,
|
||||||
"measure_id": c.MeasureID,
|
"measure_id": c.MeasureID,
|
||||||
"name": c.Name,
|
"name": c.Name,
|
||||||
"description": c.Description,
|
"description": c.Description,
|
||||||
@@ -229,6 +238,54 @@ RETURNING
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Tasks) LoadByOrganizationID(
|
||||||
|
ctx context.Context,
|
||||||
|
conn pg.Conn,
|
||||||
|
scope Scoper,
|
||||||
|
organizationID gid.GID,
|
||||||
|
cursor *page.Cursor[TaskOrderField],
|
||||||
|
) error {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
measure_id,
|
||||||
|
organization_id,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
state,
|
||||||
|
reference_id,
|
||||||
|
time_estimate,
|
||||||
|
assigned_to,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM
|
||||||
|
tasks
|
||||||
|
WHERE
|
||||||
|
%s
|
||||||
|
AND organization_id = @organization_id
|
||||||
|
AND %s
|
||||||
|
`
|
||||||
|
q = fmt.Sprintf(q, scope.SQLFragment(), cursor.SQLFragment())
|
||||||
|
|
||||||
|
args := pgx.StrictNamedArgs{"organization_id": organizationID}
|
||||||
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
maps.Copy(args, cursor.SQLArguments())
|
||||||
|
|
||||||
|
rows, err := conn.Query(ctx, q, args)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot query tasks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[Task])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot collect tasks: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*c = tasks
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Tasks) LoadByMeasureID(
|
func (c *Tasks) LoadByMeasureID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
@@ -240,6 +297,7 @@ func (c *Tasks) LoadByMeasureID(
|
|||||||
SELECT
|
SELECT
|
||||||
id,
|
id,
|
||||||
measure_id,
|
measure_id,
|
||||||
|
organization_id,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
state,
|
state,
|
||||||
@@ -288,7 +346,8 @@ SET
|
|||||||
description = @description,
|
description = @description,
|
||||||
state = @state,
|
state = @state,
|
||||||
time_estimate = @time_estimate,
|
time_estimate = @time_estimate,
|
||||||
updated_at = @updated_at
|
updated_at = @updated_at,
|
||||||
|
assigned_to = @assigned_to
|
||||||
WHERE %s
|
WHERE %s
|
||||||
AND id = @task_id
|
AND id = @task_id
|
||||||
`
|
`
|
||||||
@@ -301,6 +360,7 @@ WHERE %s
|
|||||||
"state": c.State,
|
"state": c.State,
|
||||||
"time_estimate": c.TimeEstimate,
|
"time_estimate": c.TimeEstimate,
|
||||||
"updated_at": c.UpdatedAt,
|
"updated_at": c.UpdatedAt,
|
||||||
|
"assigned_to": c.AssignedToID,
|
||||||
}
|
}
|
||||||
|
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
@@ -309,102 +369,6 @@ WHERE %s
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Task) AssignTo(
|
|
||||||
ctx context.Context,
|
|
||||||
conn pg.Conn,
|
|
||||||
scope Scoper,
|
|
||||||
assignTo gid.GID,
|
|
||||||
) error {
|
|
||||||
q := `
|
|
||||||
UPDATE tasks SET
|
|
||||||
assigned_to = @assigned_to,
|
|
||||||
updated_at = @updated_at
|
|
||||||
WHERE %s
|
|
||||||
AND id = @task_id
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
measure_id,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
reference_id,
|
|
||||||
state,
|
|
||||||
time_estimate,
|
|
||||||
assigned_to,
|
|
||||||
created_at,
|
|
||||||
updated_at
|
|
||||||
`
|
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
|
||||||
|
|
||||||
args := pgx.NamedArgs{
|
|
||||||
"task_id": c.ID,
|
|
||||||
"assigned_to": assignTo,
|
|
||||||
"updated_at": time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
maps.Copy(args, scope.SQLArguments())
|
|
||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot query tasks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
task, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Task])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot collect tasks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*c = task
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Task) Unassign(
|
|
||||||
ctx context.Context,
|
|
||||||
conn pg.Conn,
|
|
||||||
scope Scoper,
|
|
||||||
) error {
|
|
||||||
q := `
|
|
||||||
UPDATE tasks SET
|
|
||||||
assigned_to = NULL,
|
|
||||||
updated_at = @updated_at
|
|
||||||
WHERE %s
|
|
||||||
AND id = @task_id
|
|
||||||
RETURNING
|
|
||||||
id,
|
|
||||||
measure_id,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
reference_id,
|
|
||||||
state,
|
|
||||||
time_estimate,
|
|
||||||
assigned_to,
|
|
||||||
created_at,
|
|
||||||
updated_at
|
|
||||||
`
|
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment())
|
|
||||||
|
|
||||||
args := pgx.NamedArgs{
|
|
||||||
"task_id": c.ID,
|
|
||||||
"updated_at": time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
maps.Copy(args, scope.SQLArguments())
|
|
||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot query tasks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
task, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[Task])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot collect tasks: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
*c = task
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Task) Delete(
|
func (c *Task) Delete(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -119,8 +119,12 @@ func (s EvidenceService) Request(
|
|||||||
return fmt.Errorf("cannot load task: %w", err)
|
return fmt.Errorf("cannot load task: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if task.MeasureID == nil {
|
||||||
|
return fmt.Errorf("task %q has no measure", req.TaskID)
|
||||||
|
}
|
||||||
|
|
||||||
evidence.TaskID = req.TaskID
|
evidence.TaskID = req.TaskID
|
||||||
evidence.MeasureID = task.MeasureID
|
evidence.MeasureID = *task.MeasureID
|
||||||
} else if req.MeasureID != nil {
|
} else if req.MeasureID != nil {
|
||||||
evidence.MeasureID = *req.MeasureID
|
evidence.MeasureID = *req.MeasureID
|
||||||
} else {
|
} else {
|
||||||
@@ -298,7 +302,11 @@ func (s EvidenceService) UploadTaskEvidence(
|
|||||||
return fmt.Errorf("cannot load task %q: %w", req.TaskID, err)
|
return fmt.Errorf("cannot load task %q: %w", req.TaskID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
evidence.MeasureID = task.MeasureID
|
if task.MeasureID == nil {
|
||||||
|
return fmt.Errorf("task %q has no measure", req.TaskID)
|
||||||
|
}
|
||||||
|
|
||||||
|
evidence.MeasureID = *task.MeasureID
|
||||||
|
|
||||||
if err := evidence.Insert(ctx, conn, s.svc.scope); err != nil {
|
if err := evidence.Insert(ctx, conn, s.svc.scope); err != nil {
|
||||||
return fmt.Errorf("cannot insert evidence: %w", err)
|
return fmt.Errorf("cannot insert evidence: %w", err)
|
||||||
|
|||||||
@@ -169,7 +169,8 @@ func (s MeasureService) Import(
|
|||||||
|
|
||||||
task := &coredata.Task{
|
task := &coredata.Task{
|
||||||
ID: taskID,
|
ID: taskID,
|
||||||
MeasureID: measure.ID,
|
OrganizationID: organizationID,
|
||||||
|
MeasureID: &measure.ID,
|
||||||
Name: req.Measures[i].Tasks[j].Name,
|
Name: req.Measures[i].Tasks[j].Name,
|
||||||
Description: req.Measures[i].Tasks[j].Description,
|
Description: req.Measures[i].Tasks[j].Description,
|
||||||
ReferenceID: req.Measures[i].Tasks[j].ReferenceID,
|
ReferenceID: req.Measures[i].Tasks[j].ReferenceID,
|
||||||
@@ -32,7 +32,8 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
CreateTaskRequest struct {
|
CreateTaskRequest struct {
|
||||||
MeasureID gid.GID
|
OrganizationID gid.GID
|
||||||
|
MeasureID *gid.GID
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
TimeEstimate *time.Duration
|
TimeEstimate *time.Duration
|
||||||
@@ -62,6 +63,7 @@ func (s TaskService) Create(
|
|||||||
|
|
||||||
task := &coredata.Task{
|
task := &coredata.Task{
|
||||||
ID: taskID,
|
ID: taskID,
|
||||||
|
OrganizationID: req.OrganizationID,
|
||||||
MeasureID: req.MeasureID,
|
MeasureID: req.MeasureID,
|
||||||
Name: req.Name,
|
Name: req.Name,
|
||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
@@ -76,6 +78,7 @@ func (s TaskService) Create(
|
|||||||
err = s.svc.pg.WithTx(
|
err = s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(conn pg.Conn) error {
|
func(conn pg.Conn) error {
|
||||||
|
|
||||||
if err := task.Insert(ctx, conn, s.svc.scope); err != nil {
|
if err := task.Insert(ctx, conn, s.svc.scope); err != nil {
|
||||||
return fmt.Errorf("cannot insert task: %w", err)
|
return fmt.Errorf("cannot insert task: %w", err)
|
||||||
}
|
}
|
||||||
@@ -119,7 +122,18 @@ func (s TaskService) Assign(
|
|||||||
err := s.svc.pg.WithTx(
|
err := s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(conn pg.Conn) error {
|
func(conn pg.Conn) error {
|
||||||
return task.AssignTo(ctx, conn, s.svc.scope, assignedToID)
|
if err := task.LoadByID(ctx, conn, s.svc.scope, taskID); err != nil {
|
||||||
|
return fmt.Errorf("cannot load task %q: %w", taskID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
task.AssignedToID = &assignedToID
|
||||||
|
task.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := task.Update(ctx, conn, s.svc.scope); err != nil {
|
||||||
|
return fmt.Errorf("cannot assign task %q to %q: %w", taskID, assignedToID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -133,12 +147,23 @@ func (s TaskService) Unassign(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
taskID gid.GID,
|
taskID gid.GID,
|
||||||
) (*coredata.Task, error) {
|
) (*coredata.Task, error) {
|
||||||
task := &coredata.Task{ID: taskID}
|
task := &coredata.Task{}
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(
|
err := s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
func(conn pg.Conn) error {
|
func(conn pg.Conn) error {
|
||||||
return task.Unassign(ctx, conn, s.svc.scope)
|
if err := task.LoadByID(ctx, conn, s.svc.scope, taskID); err != nil {
|
||||||
|
return fmt.Errorf("cannot load task %q: %w", taskID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
task.AssignedToID = nil
|
||||||
|
task.UpdatedAt = time.Now()
|
||||||
|
|
||||||
|
if err := task.Update(ctx, conn, s.svc.scope); err != nil {
|
||||||
|
return fmt.Errorf("cannot unassign task %q: %w", taskID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -152,7 +177,8 @@ func (s TaskService) Update(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req UpdateTaskRequest,
|
req UpdateTaskRequest,
|
||||||
) (*coredata.Task, error) {
|
) (*coredata.Task, error) {
|
||||||
task := &coredata.Task{ID: req.TaskID}
|
|
||||||
|
task := &coredata.Task{}
|
||||||
|
|
||||||
err := s.svc.pg.WithTx(
|
err := s.svc.pg.WithTx(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -212,6 +238,26 @@ func (s TaskService) Delete(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s TaskService) ListForOrganizationID(
|
||||||
|
ctx context.Context,
|
||||||
|
organizationID gid.GID,
|
||||||
|
cursor *page.Cursor[coredata.TaskOrderField],
|
||||||
|
) (*page.Page[*coredata.Task, coredata.TaskOrderField], error) {
|
||||||
|
var tasks coredata.Tasks
|
||||||
|
|
||||||
|
err := s.svc.pg.WithConn(
|
||||||
|
ctx,
|
||||||
|
func(conn pg.Conn) error {
|
||||||
|
return tasks.LoadByOrganizationID(ctx, conn, s.svc.scope, organizationID, cursor)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return page.NewPage(tasks, cursor), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s TaskService) ListForMeasureID(
|
func (s TaskService) ListForMeasureID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
measureID gid.GID,
|
measureID gid.GID,
|
||||||
|
|||||||
@@ -461,6 +461,14 @@ type Organization implements Node {
|
|||||||
orderBy: RiskOrder
|
orderBy: RiskOrder
|
||||||
): RiskConnection! @goField(forceResolver: true)
|
): RiskConnection! @goField(forceResolver: true)
|
||||||
|
|
||||||
|
tasks(
|
||||||
|
first: Int
|
||||||
|
after: CursorKey
|
||||||
|
last: Int
|
||||||
|
before: CursorKey
|
||||||
|
orderBy: TaskOrder
|
||||||
|
): TaskConnection! @goField(forceResolver: true)
|
||||||
|
|
||||||
createdAt: Datetime!
|
createdAt: Datetime!
|
||||||
updatedAt: Datetime!
|
updatedAt: Datetime!
|
||||||
}
|
}
|
||||||
@@ -498,6 +506,8 @@ type Vendor implements Node {
|
|||||||
name: String!
|
name: String!
|
||||||
description: String
|
description: String
|
||||||
|
|
||||||
|
organization: Organization! @goField(forceResolver: true)
|
||||||
|
|
||||||
complianceReports(
|
complianceReports(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
@@ -538,10 +548,8 @@ type VendorComplianceReport implements Node {
|
|||||||
reportDate: Datetime!
|
reportDate: Datetime!
|
||||||
validUntil: Datetime
|
validUntil: Datetime
|
||||||
reportName: String!
|
reportName: String!
|
||||||
|
|
||||||
fileUrl: String! @goField(forceResolver: true)
|
fileUrl: String! @goField(forceResolver: true)
|
||||||
fileSize: Int!
|
fileSize: Int!
|
||||||
|
|
||||||
createdAt: Datetime!
|
createdAt: Datetime!
|
||||||
updatedAt: Datetime!
|
updatedAt: Datetime!
|
||||||
}
|
}
|
||||||
@@ -551,6 +559,8 @@ type Framework implements Node {
|
|||||||
name: String!
|
name: String!
|
||||||
description: String!
|
description: String!
|
||||||
|
|
||||||
|
organization: Organization! @goField(forceResolver: true)
|
||||||
|
|
||||||
controls(
|
controls(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
@@ -569,6 +579,8 @@ type Control implements Node {
|
|||||||
name: String!
|
name: String!
|
||||||
description: String!
|
description: String!
|
||||||
|
|
||||||
|
framework: Framework! @goField(forceResolver: true)
|
||||||
|
|
||||||
measures(
|
measures(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
@@ -640,6 +652,9 @@ type Task implements Node {
|
|||||||
timeEstimate: Duration
|
timeEstimate: Duration
|
||||||
assignedTo: People @goField(forceResolver: true)
|
assignedTo: People @goField(forceResolver: true)
|
||||||
|
|
||||||
|
organization: Organization! @goField(forceResolver: true)
|
||||||
|
measure: Measure @goField(forceResolver: true)
|
||||||
|
|
||||||
evidences(
|
evidences(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
@@ -663,6 +678,9 @@ type Evidence implements Node {
|
|||||||
url: String
|
url: String
|
||||||
description: String!
|
description: String!
|
||||||
|
|
||||||
|
task: Task @goField(forceResolver: true)
|
||||||
|
measure: Measure! @goField(forceResolver: true)
|
||||||
|
|
||||||
createdAt: Datetime!
|
createdAt: Datetime!
|
||||||
updatedAt: Datetime!
|
updatedAt: Datetime!
|
||||||
}
|
}
|
||||||
@@ -673,6 +691,7 @@ type Policy implements Node {
|
|||||||
description: String!
|
description: String!
|
||||||
currentPublishedVersion: Int
|
currentPublishedVersion: Int
|
||||||
owner: People! @goField(forceResolver: true)
|
owner: People! @goField(forceResolver: true)
|
||||||
|
organization: Organization! @goField(forceResolver: true)
|
||||||
|
|
||||||
versions(
|
versions(
|
||||||
first: Int
|
first: Int
|
||||||
@@ -710,6 +729,7 @@ type Risk implements Node {
|
|||||||
note: String!
|
note: String!
|
||||||
|
|
||||||
owner: People @goField(forceResolver: true)
|
owner: People @goField(forceResolver: true)
|
||||||
|
organization: Organization! @goField(forceResolver: true)
|
||||||
|
|
||||||
measures(
|
measures(
|
||||||
first: Int
|
first: Int
|
||||||
@@ -1140,7 +1160,8 @@ input ImportMeasureInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input CreateTaskInput {
|
input CreateTaskInput {
|
||||||
measureId: ID!
|
organizationId: ID!
|
||||||
|
measureId: ID
|
||||||
name: String!
|
name: String!
|
||||||
description: String!
|
description: String!
|
||||||
timeEstimate: Duration
|
timeEstimate: Duration
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -67,6 +67,7 @@ type Control struct {
|
|||||||
ReferenceID string `json:"referenceId"`
|
ReferenceID string `json:"referenceId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
Framework *Framework `json:"framework"`
|
||||||
Measures *MeasureConnection `json:"measures"`
|
Measures *MeasureConnection `json:"measures"`
|
||||||
Policies *PolicyConnection `json:"policies"`
|
Policies *PolicyConnection `json:"policies"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
@@ -215,7 +216,8 @@ type CreateRiskPolicyMappingPayload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateTaskInput struct {
|
type CreateTaskInput struct {
|
||||||
MeasureID gid.GID `json:"measureId"`
|
OrganizationID gid.GID `json:"organizationId"`
|
||||||
|
MeasureID *gid.GID `json:"measureId,omitempty"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
|
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
|
||||||
@@ -389,6 +391,8 @@ type Evidence struct {
|
|||||||
Filename string `json:"filename"`
|
Filename string `json:"filename"`
|
||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
Task *Task `json:"task,omitempty"`
|
||||||
|
Measure *Measure `json:"measure"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
}
|
}
|
||||||
@@ -410,6 +414,7 @@ type Framework struct {
|
|||||||
ID gid.GID `json:"id"`
|
ID gid.GID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
Organization *Organization `json:"organization"`
|
||||||
Controls *ControlConnection `json:"controls"`
|
Controls *ControlConnection `json:"controls"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
@@ -509,6 +514,7 @@ type Organization struct {
|
|||||||
Policies *PolicyConnection `json:"policies"`
|
Policies *PolicyConnection `json:"policies"`
|
||||||
Measures *MeasureConnection `json:"measures"`
|
Measures *MeasureConnection `json:"measures"`
|
||||||
Risks *RiskConnection `json:"risks"`
|
Risks *RiskConnection `json:"risks"`
|
||||||
|
Tasks *TaskConnection `json:"tasks"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
}
|
}
|
||||||
@@ -567,6 +573,7 @@ type Policy struct {
|
|||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
CurrentPublishedVersion *int `json:"currentPublishedVersion,omitempty"`
|
CurrentPublishedVersion *int `json:"currentPublishedVersion,omitempty"`
|
||||||
Owner *People `json:"owner"`
|
Owner *People `json:"owner"`
|
||||||
|
Organization *Organization `json:"organization"`
|
||||||
Versions *PolicyVersionConnection `json:"versions"`
|
Versions *PolicyVersionConnection `json:"versions"`
|
||||||
Controls *ControlConnection `json:"controls"`
|
Controls *ControlConnection `json:"controls"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
@@ -702,6 +709,7 @@ type Risk struct {
|
|||||||
ResidualSeverity int `json:"residualSeverity"`
|
ResidualSeverity int `json:"residualSeverity"`
|
||||||
Note string `json:"note"`
|
Note string `json:"note"`
|
||||||
Owner *People `json:"owner,omitempty"`
|
Owner *People `json:"owner,omitempty"`
|
||||||
|
Organization *Organization `json:"organization"`
|
||||||
Measures *MeasureConnection `json:"measures"`
|
Measures *MeasureConnection `json:"measures"`
|
||||||
Policies *PolicyConnection `json:"policies"`
|
Policies *PolicyConnection `json:"policies"`
|
||||||
Controls *ControlConnection `json:"controls"`
|
Controls *ControlConnection `json:"controls"`
|
||||||
@@ -742,6 +750,8 @@ type Task struct {
|
|||||||
State coredata.TaskState `json:"state"`
|
State coredata.TaskState `json:"state"`
|
||||||
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
|
TimeEstimate *time.Duration `json:"timeEstimate,omitempty"`
|
||||||
AssignedTo *People `json:"assignedTo,omitempty"`
|
AssignedTo *People `json:"assignedTo,omitempty"`
|
||||||
|
Organization *Organization `json:"organization"`
|
||||||
|
Measure *Measure `json:"measure,omitempty"`
|
||||||
Evidences *EvidenceConnection `json:"evidences"`
|
Evidences *EvidenceConnection `json:"evidences"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
@@ -943,6 +953,7 @@ type Vendor struct {
|
|||||||
ID gid.GID `json:"id"`
|
ID gid.GID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description *string `json:"description,omitempty"`
|
Description *string `json:"description,omitempty"`
|
||||||
|
Organization *Organization `json:"organization"`
|
||||||
ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"`
|
ComplianceReports *VendorComplianceReportConnection `json:"complianceReports"`
|
||||||
RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"`
|
RiskAssessments *VendorRiskAssessmentConnection `json:"riskAssessments"`
|
||||||
BusinessOwner *People `json:"businessOwner,omitempty"`
|
BusinessOwner *People `json:"businessOwner,omitempty"`
|
||||||
|
|||||||
@@ -20,6 +20,23 @@ import (
|
|||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Framework is the resolver for the framework field.
|
||||||
|
func (r *controlResolver) Framework(ctx context.Context, obj *types.Control) (*types.Framework, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
control, err := svc.Controls.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get control: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
framework, err := svc.Frameworks.Get(ctx, control.FrameworkID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get framework: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewFramework(framework), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Measures is the resolver for the measures field.
|
// Measures is the resolver for the measures field.
|
||||||
func (r *controlResolver) Measures(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy) (*types.MeasureConnection, error) {
|
func (r *controlResolver) Measures(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy) (*types.MeasureConnection, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
@@ -87,6 +104,61 @@ func (r *evidenceResolver) FileURL(ctx context.Context, obj *types.Evidence) (*s
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Task is the resolver for the task field.
|
||||||
|
func (r *evidenceResolver) Task(ctx context.Context, obj *types.Evidence) (*types.Task, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
evidence, err := svc.Evidences.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load evidence: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if evidence.TaskID == nil {
|
||||||
|
return nil, fmt.Errorf("evidence is not associated with a task")
|
||||||
|
}
|
||||||
|
|
||||||
|
task, err := svc.Tasks.Get(ctx, *evidence.TaskID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load task: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewTask(task), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure is the resolver for the measure field.
|
||||||
|
func (r *evidenceResolver) Measure(ctx context.Context, obj *types.Evidence) (*types.Measure, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
evidence, err := svc.Evidences.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load evidence: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
measure, err := svc.Measures.Get(ctx, evidence.MeasureID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load measure: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewMeasure(measure), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Organization is the resolver for the organization field.
|
||||||
|
func (r *frameworkResolver) Organization(ctx context.Context, obj *types.Framework) (*types.Organization, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
framework, err := svc.Frameworks.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load framework: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
organization, err := svc.Organizations.Get(ctx, framework.OrganizationID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load organization: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewOrganization(organization), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Controls is the resolver for the controls field.
|
// Controls is the resolver for the controls field.
|
||||||
func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy) (*types.ControlConnection, error) {
|
func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy) (*types.ControlConnection, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
@@ -690,6 +762,7 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTas
|
|||||||
|
|
||||||
task, err := svc.Tasks.Create(ctx, probo.CreateTaskRequest{
|
task, err := svc.Tasks.Create(ctx, probo.CreateTaskRequest{
|
||||||
MeasureID: input.MeasureID,
|
MeasureID: input.MeasureID,
|
||||||
|
OrganizationID: input.OrganizationID,
|
||||||
Name: input.Name,
|
Name: input.Name,
|
||||||
Description: input.Description,
|
Description: input.Description,
|
||||||
TimeEstimate: input.TimeEstimate,
|
TimeEstimate: input.TimeEstimate,
|
||||||
@@ -1416,6 +1489,31 @@ func (r *organizationResolver) Risks(ctx context.Context, obj *types.Organizatio
|
|||||||
return types.NewRiskConnection(page), nil
|
return types.NewRiskConnection(page), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tasks is the resolver for the tasks field.
|
||||||
|
func (r *organizationResolver) Tasks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
pageOrderBy := page.OrderBy[coredata.TaskOrderField]{
|
||||||
|
Field: coredata.TaskOrderFieldCreatedAt,
|
||||||
|
Direction: page.OrderDirectionDesc,
|
||||||
|
}
|
||||||
|
if orderBy != nil {
|
||||||
|
pageOrderBy = page.OrderBy[coredata.TaskOrderField]{
|
||||||
|
Field: orderBy.Field,
|
||||||
|
Direction: orderBy.Direction,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := types.NewCursor(first, after, last, before, pageOrderBy)
|
||||||
|
|
||||||
|
page, err := svc.Tasks.ListForOrganizationID(ctx, obj.ID, cursor)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot list organization tasks: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewTaskConnection(page), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Owner is the resolver for the owner field.
|
// Owner is the resolver for the owner field.
|
||||||
func (r *policyResolver) Owner(ctx context.Context, obj *types.Policy) (*types.People, error) {
|
func (r *policyResolver) Owner(ctx context.Context, obj *types.Policy) (*types.People, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
@@ -1434,6 +1532,23 @@ func (r *policyResolver) Owner(ctx context.Context, obj *types.Policy) (*types.P
|
|||||||
return types.NewPeople(owner), nil
|
return types.NewPeople(owner), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Organization is the resolver for the organization field.
|
||||||
|
func (r *policyResolver) Organization(ctx context.Context, obj *types.Policy) (*types.Organization, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
policy, err := svc.Policies.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get policy: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
organization, err := svc.Organizations.Get(ctx, policy.OrganizationID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get organization: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewOrganization(organization), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Versions is the resolver for the versions field.
|
// Versions is the resolver for the versions field.
|
||||||
func (r *policyResolver) Versions(ctx context.Context, obj *types.Policy, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyVersionOrderBy, filter *types.PolicyVersionFilter) (*types.PolicyVersionConnection, error) {
|
func (r *policyResolver) Versions(ctx context.Context, obj *types.Policy, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PolicyVersionOrderBy, filter *types.PolicyVersionFilter) (*types.PolicyVersionConnection, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
@@ -1727,6 +1842,23 @@ func (r *riskResolver) Owner(ctx context.Context, obj *types.Risk) (*types.Peopl
|
|||||||
return types.NewPeople(owner), nil
|
return types.NewPeople(owner), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Organization is the resolver for the organization field.
|
||||||
|
func (r *riskResolver) Organization(ctx context.Context, obj *types.Risk) (*types.Organization, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
risk, err := svc.Risks.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get risk: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
organization, err := svc.Organizations.Get(ctx, risk.OrganizationID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get organization: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewOrganization(organization), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Measures is the resolver for the measures field.
|
// Measures is the resolver for the measures field.
|
||||||
func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy) (*types.MeasureConnection, error) {
|
func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy) (*types.MeasureConnection, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
@@ -1823,6 +1955,40 @@ func (r *taskResolver) AssignedTo(ctx context.Context, obj *types.Task) (*types.
|
|||||||
return types.NewPeople(people), nil
|
return types.NewPeople(people), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Organization is the resolver for the organization field.
|
||||||
|
func (r *taskResolver) Organization(ctx context.Context, obj *types.Task) (*types.Organization, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
task, err := svc.Tasks.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get task: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
organization, err := svc.Organizations.Get(ctx, task.OrganizationID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get organization: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewOrganization(organization), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure is the resolver for the measure field.
|
||||||
|
func (r *taskResolver) Measure(ctx context.Context, obj *types.Task) (*types.Measure, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
task, err := svc.Tasks.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get task: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
measure, err := svc.Measures.Get(ctx, *task.MeasureID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get measure: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewMeasure(measure), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Evidences is the resolver for the evidences field.
|
// Evidences is the resolver for the evidences field.
|
||||||
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
@@ -1859,6 +2025,23 @@ func (r *userResolver) People(ctx context.Context, obj *types.User, organization
|
|||||||
return types.NewPeople(people), nil
|
return types.NewPeople(people), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Organization is the resolver for the organization field.
|
||||||
|
func (r *vendorResolver) Organization(ctx context.Context, obj *types.Vendor) (*types.Organization, error) {
|
||||||
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|
||||||
|
vendor, err := svc.Vendors.Get(ctx, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get vendor: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
organization, err := svc.Organizations.Get(ctx, vendor.OrganizationID)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("cannot get organization: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewOrganization(organization), nil
|
||||||
|
}
|
||||||
|
|
||||||
// ComplianceReports is the resolver for the complianceReports field.
|
// ComplianceReports is the resolver for the complianceReports field.
|
||||||
func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) {
|
func (r *vendorResolver) ComplianceReports(ctx context.Context, obj *types.Vendor, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorComplianceReportOrderBy) (*types.VendorComplianceReportConnection, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, obj.ID.TenantID())
|
||||||
|
|||||||
Reference in New Issue
Block a user