@burdenoff/planmagnet-fe-sdk 2026.706.5 → 2026.706.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +40 -2
- package/dist/index.js +167 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -740,6 +740,19 @@ interface TaskTimelineCoreProps {
|
|
|
740
740
|
resolveAssignee?: ResolveAssignee;
|
|
741
741
|
/** Fetch + flag project milestones on the timeline (default true). */
|
|
742
742
|
showMilestones?: boolean;
|
|
743
|
+
/**
|
|
744
|
+
* Allow creating milestones from the timeline (an inline name + due-date
|
|
745
|
+
* form in the milestones strip). Requires a create project (see
|
|
746
|
+
* `milestoneProjectId`). Gate on the host's manage permission. Default false.
|
|
747
|
+
*/
|
|
748
|
+
canCreateMilestone?: boolean;
|
|
749
|
+
/**
|
|
750
|
+
* Project new milestones are created under. Defaults to `projectId`. Set this
|
|
751
|
+
* when the timeline's task-filter project differs from the project milestones
|
|
752
|
+
* should belong to — e.g. an unscoped "all tasks" board that still has a
|
|
753
|
+
* default create-project.
|
|
754
|
+
*/
|
|
755
|
+
milestoneProjectId?: string;
|
|
743
756
|
className?: string;
|
|
744
757
|
workspaceId?: string;
|
|
745
758
|
}
|
|
@@ -752,7 +765,7 @@ interface TaskTimelineCoreProps {
|
|
|
752
765
|
* honest to the data. Overdue and undated work is surfaced explicitly so nothing
|
|
753
766
|
* hides. BYO-Apollo, semantic-token only, farm-free.
|
|
754
767
|
*/
|
|
755
|
-
declare function TaskTimelineCore({ projectId, priority, type, search, assigneeId, defaultMode, onSelect, resolveAssignee, showMilestones, className, workspaceId: workspaceIdProp, }: TaskTimelineCoreProps): react.JSX.Element;
|
|
768
|
+
declare function TaskTimelineCore({ projectId, priority, type, search, assigneeId, defaultMode, onSelect, resolveAssignee, showMilestones, canCreateMilestone, milestoneProjectId, className, workspaceId: workspaceIdProp, }: TaskTimelineCoreProps): react.JSX.Element;
|
|
756
769
|
|
|
757
770
|
/** The three task views the toolbar can switch between. */
|
|
758
771
|
type TaskView = "board" | "list" | "timeline";
|
|
@@ -946,6 +959,9 @@ interface TaskLabels {
|
|
|
946
959
|
overdue: string;
|
|
947
960
|
noDueDate: string;
|
|
948
961
|
milestones: string;
|
|
962
|
+
addMilestone: string;
|
|
963
|
+
milestoneNamePlaceholder: string;
|
|
964
|
+
failedToCreateMilestone: string;
|
|
949
965
|
today: string;
|
|
950
966
|
week: string;
|
|
951
967
|
month: string;
|
|
@@ -1061,6 +1077,11 @@ interface TasksPageCoreProps {
|
|
|
1061
1077
|
columns?: BoardColumn[];
|
|
1062
1078
|
/** Read-only — hides the "New task" button, disables drag + detail editing. */
|
|
1063
1079
|
readonly?: boolean;
|
|
1080
|
+
/**
|
|
1081
|
+
* Allow creating milestones from the Timeline view (inline form in the
|
|
1082
|
+
* milestones strip). Requires a `boardProjectId`. Defaults to `!readonly`.
|
|
1083
|
+
*/
|
|
1084
|
+
canCreateMilestone?: boolean;
|
|
1064
1085
|
/**
|
|
1065
1086
|
* Field names to hide across the board cards, create form, and detail view.
|
|
1066
1087
|
* A product-agnostic hook so hosts can suppress fields that don't apply.
|
|
@@ -1137,7 +1158,7 @@ interface TasksPageCoreProps {
|
|
|
1137
1158
|
* BYO-Apollo: reads the ambient `<ApolloProvider>` and takes `workspaceId` from
|
|
1138
1159
|
* a prop or the PlanMagnetProvider context. Semantic tokens only, farm-free.
|
|
1139
1160
|
*/
|
|
1140
|
-
declare function TasksPageCore({ workspaceId: workspaceIdProp, projectId, boardProjectId, columns, readonly, hiddenFields, views, defaultView, confirmMove, resolveAssignee, linkSourceProduct, renderLinkIcon, assigneeOptions, currentActorId, commentsEntityType, onMention, labels, openItemId, header, onTaskSaved, createSurface, detailSurface, className, }: TasksPageCoreProps): react.JSX.Element;
|
|
1161
|
+
declare function TasksPageCore({ workspaceId: workspaceIdProp, projectId, boardProjectId, columns, readonly, canCreateMilestone, hiddenFields, views, defaultView, confirmMove, resolveAssignee, linkSourceProduct, renderLinkIcon, assigneeOptions, currentActorId, commentsEntityType, onMention, labels, openItemId, header, onTaskSaved, createSurface, detailSurface, className, }: TasksPageCoreProps): react.JSX.Element;
|
|
1141
1162
|
|
|
1142
1163
|
interface TasksPageProps extends TasksPageCoreProps {
|
|
1143
1164
|
/** Workspace API gateway URL (URL mode). */
|
|
@@ -1255,11 +1276,28 @@ interface UseWorkItemLinksResult {
|
|
|
1255
1276
|
*/
|
|
1256
1277
|
declare function useWorkItemLinks(workspaceId: string | undefined, sourceProduct: string | undefined, limit?: number): UseWorkItemLinksResult;
|
|
1257
1278
|
|
|
1279
|
+
/** Args for creating a milestone (subset of PlanmagnetCreateMilestoneInput). */
|
|
1280
|
+
interface CreateMilestoneArgs {
|
|
1281
|
+
projectId: string;
|
|
1282
|
+
name: string;
|
|
1283
|
+
/** A `yyyy-MM-dd` day; stored on the DateTime column at local noon. */
|
|
1284
|
+
dueDate?: string | null;
|
|
1285
|
+
status?: MilestoneStatus;
|
|
1286
|
+
description?: string | null;
|
|
1287
|
+
}
|
|
1258
1288
|
interface UseMilestonesResult {
|
|
1259
1289
|
milestones: Milestone[];
|
|
1260
1290
|
/** Milestones grouped by their due day (yyyy-MM-dd), for timeline flags. */
|
|
1261
1291
|
byDay: Map<string, Milestone[]>;
|
|
1262
1292
|
loading: boolean;
|
|
1293
|
+
/** True while a create mutation is in flight. */
|
|
1294
|
+
creating: boolean;
|
|
1295
|
+
/**
|
|
1296
|
+
* Create a milestone and refetch the list. Returns the created milestone, or
|
|
1297
|
+
* throws so the caller can surface a toast. A `yyyy-MM-dd` dueDate is stored
|
|
1298
|
+
* at local noon so it lands on the intended day regardless of timezone.
|
|
1299
|
+
*/
|
|
1300
|
+
createMilestone: (args: CreateMilestoneArgs) => Promise<Milestone | null>;
|
|
1263
1301
|
}
|
|
1264
1302
|
/**
|
|
1265
1303
|
* useMilestones — fetch a project's milestones (e.g. a harvest window) for the
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { onError } from '@apollo/client/link/error';
|
|
|
6
6
|
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
|
7
7
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
8
8
|
import { gql } from '@apollo/client';
|
|
9
|
-
import { CircleX, CircleCheckBig, CircleDotDashed, CircleDot, Circle, CircleDashed, User, Link2, CalendarDays, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Flag, CalendarRange, List, LayoutGrid, Search,
|
|
9
|
+
import { CircleX, CircleCheckBig, CircleDotDashed, CircleDot, Circle, CircleDashed, User, Link2, CalendarDays, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Flag, Plus, CalendarRange, List, LayoutGrid, Search, Trash2 } from 'lucide-react';
|
|
10
10
|
import { clsx } from 'clsx';
|
|
11
11
|
import { twMerge } from 'tailwind-merge';
|
|
12
12
|
import { addWeeks, startOfWeek, endOfWeek, eachDayOfInterval, addMonths, startOfMonth, endOfMonth, format, isToday, isSameMonth, startOfDay, parseISO, isValid } from 'date-fns';
|
|
@@ -507,6 +507,14 @@ var LIST_MILESTONES = gql`
|
|
|
507
507
|
}
|
|
508
508
|
${MILESTONE_FIELDS}
|
|
509
509
|
`;
|
|
510
|
+
var CREATE_MILESTONE = gql`
|
|
511
|
+
mutation CreateMilestone($input: PlanmagnetCreateMilestoneInput!) {
|
|
512
|
+
planmagnetCreateMilestone(input: $input) {
|
|
513
|
+
...MilestoneFields
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
${MILESTONE_FIELDS}
|
|
517
|
+
`;
|
|
510
518
|
var DELETE_WORK_ITEM = gql`
|
|
511
519
|
mutation DeleteWorkItem($id: ID!) {
|
|
512
520
|
planmagnetDeleteWorkItem(id: $id)
|
|
@@ -772,6 +780,9 @@ var DEFAULT_TASK_LABELS = {
|
|
|
772
780
|
overdue: "{n} overdue",
|
|
773
781
|
noDueDate: "No due date ({n})",
|
|
774
782
|
milestones: "Milestones",
|
|
783
|
+
addMilestone: "Add milestone",
|
|
784
|
+
milestoneNamePlaceholder: "Milestone name",
|
|
785
|
+
failedToCreateMilestone: "Failed to create milestone",
|
|
775
786
|
today: "Today",
|
|
776
787
|
week: "Week",
|
|
777
788
|
month: "Month",
|
|
@@ -1996,17 +2007,52 @@ function TaskList({
|
|
|
1996
2007
|
}
|
|
1997
2008
|
);
|
|
1998
2009
|
}
|
|
2010
|
+
function dayToLocalNoonIso(day) {
|
|
2011
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(day);
|
|
2012
|
+
if (!m) return void 0;
|
|
2013
|
+
return new Date(
|
|
2014
|
+
Number(m[1]),
|
|
2015
|
+
Number(m[2]) - 1,
|
|
2016
|
+
Number(m[3]),
|
|
2017
|
+
12,
|
|
2018
|
+
0,
|
|
2019
|
+
0
|
|
2020
|
+
).toISOString();
|
|
2021
|
+
}
|
|
1999
2022
|
function useMilestones(workspaceId, opts = {}) {
|
|
2000
2023
|
const { projectId, enabled = true, limit = 100 } = opts;
|
|
2001
|
-
const { data, loading } = useQuery(
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2024
|
+
const { data, loading, refetch } = useQuery(
|
|
2025
|
+
LIST_MILESTONES,
|
|
2026
|
+
{
|
|
2027
|
+
variables: {
|
|
2028
|
+
workspaceId,
|
|
2029
|
+
...projectId ? { filter: { projectId } } : {},
|
|
2030
|
+
pagination: { first: limit }
|
|
2031
|
+
},
|
|
2032
|
+
skip: !workspaceId || !enabled,
|
|
2033
|
+
errorPolicy: "all"
|
|
2034
|
+
}
|
|
2035
|
+
);
|
|
2036
|
+
const [createMutation, { loading: creating }] = useMutation(CREATE_MILESTONE);
|
|
2037
|
+
const createMilestone = useCallback(
|
|
2038
|
+
async (args) => {
|
|
2039
|
+
const iso = args.dueDate ? dayToLocalNoonIso(args.dueDate) : void 0;
|
|
2040
|
+
const res = await createMutation({
|
|
2041
|
+
variables: {
|
|
2042
|
+
input: {
|
|
2043
|
+
projectId: args.projectId,
|
|
2044
|
+
name: args.name,
|
|
2045
|
+
...iso ? { dueDate: iso } : {},
|
|
2046
|
+
...args.status ? { status: args.status } : {},
|
|
2047
|
+
...args.description ? { description: args.description } : {}
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
});
|
|
2051
|
+
await refetch();
|
|
2052
|
+
return res.data?.planmagnetCreateMilestone ?? null;
|
|
2006
2053
|
},
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
});
|
|
2054
|
+
[createMutation, refetch]
|
|
2055
|
+
);
|
|
2010
2056
|
const milestones = useMemo(
|
|
2011
2057
|
() => data?.planmagnetMilestones?.items ?? [],
|
|
2012
2058
|
[data]
|
|
@@ -2023,7 +2069,7 @@ function useMilestones(workspaceId, opts = {}) {
|
|
|
2023
2069
|
}
|
|
2024
2070
|
return map;
|
|
2025
2071
|
}, [milestones]);
|
|
2026
|
-
return { milestones, byDay, loading };
|
|
2072
|
+
return { milestones, byDay, loading, creating, createMilestone };
|
|
2027
2073
|
}
|
|
2028
2074
|
var WEEK_OPTS = { weekStartsOn: 1 };
|
|
2029
2075
|
function dayKey(d) {
|
|
@@ -2039,18 +2085,49 @@ function TaskTimelineCore({
|
|
|
2039
2085
|
onSelect,
|
|
2040
2086
|
resolveAssignee,
|
|
2041
2087
|
showMilestones = true,
|
|
2088
|
+
canCreateMilestone = false,
|
|
2089
|
+
milestoneProjectId,
|
|
2042
2090
|
className,
|
|
2043
2091
|
workspaceId: workspaceIdProp
|
|
2044
2092
|
}) {
|
|
2045
2093
|
const ctx = usePlanMagnetContextSafe();
|
|
2046
2094
|
const workspaceId = workspaceIdProp ?? ctx?.workspaceId;
|
|
2047
2095
|
const L = useTaskLabels();
|
|
2048
|
-
const {
|
|
2096
|
+
const {
|
|
2097
|
+
milestones,
|
|
2098
|
+
byDay: milestonesByDay,
|
|
2099
|
+
creating: creatingMilestone,
|
|
2100
|
+
createMilestone
|
|
2101
|
+
} = useMilestones(workspaceId, {
|
|
2049
2102
|
projectId,
|
|
2050
2103
|
enabled: showMilestones
|
|
2051
2104
|
});
|
|
2052
2105
|
const [mode, setMode] = useState(defaultMode);
|
|
2053
2106
|
const [offset, setOffset] = useState(0);
|
|
2107
|
+
const milestoneProject = milestoneProjectId ?? projectId;
|
|
2108
|
+
const canAddMilestone = canCreateMilestone && Boolean(milestoneProject);
|
|
2109
|
+
const [showMilestoneForm, setShowMilestoneForm] = useState(false);
|
|
2110
|
+
const [milestoneName, setMilestoneName] = useState("");
|
|
2111
|
+
const [milestoneDue, setMilestoneDue] = useState("");
|
|
2112
|
+
const [milestoneError, setMilestoneError] = useState(null);
|
|
2113
|
+
const submitMilestone = async (e) => {
|
|
2114
|
+
e.preventDefault();
|
|
2115
|
+
const name = milestoneName.trim();
|
|
2116
|
+
if (!name || !milestoneProject) return;
|
|
2117
|
+
setMilestoneError(null);
|
|
2118
|
+
try {
|
|
2119
|
+
await createMilestone({
|
|
2120
|
+
projectId: milestoneProject,
|
|
2121
|
+
name,
|
|
2122
|
+
dueDate: milestoneDue || void 0
|
|
2123
|
+
});
|
|
2124
|
+
setMilestoneName("");
|
|
2125
|
+
setMilestoneDue("");
|
|
2126
|
+
setShowMilestoneForm(false);
|
|
2127
|
+
} catch {
|
|
2128
|
+
setMilestoneError(L.failedToCreateMilestone);
|
|
2129
|
+
}
|
|
2130
|
+
};
|
|
2054
2131
|
const { data, loading, error } = useQuery(
|
|
2055
2132
|
LIST_WORK_ITEMS,
|
|
2056
2133
|
{
|
|
@@ -2198,12 +2275,82 @@ function TaskTimelineCore({
|
|
|
2198
2275
|
t.id
|
|
2199
2276
|
)) })
|
|
2200
2277
|
] }),
|
|
2201
|
-
milestones.length > 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2", children: [
|
|
2202
|
-
/* @__PURE__ */ jsxs("
|
|
2203
|
-
/* @__PURE__ */
|
|
2204
|
-
|
|
2278
|
+
(milestones.length > 0 || canAddMilestone) && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/5 px-3 py-2", children: [
|
|
2279
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-1 flex items-center justify-between gap-2", children: [
|
|
2280
|
+
/* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1 text-xs font-semibold text-primary", children: [
|
|
2281
|
+
/* @__PURE__ */ jsx(Flag, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
|
|
2282
|
+
L.milestones
|
|
2283
|
+
] }),
|
|
2284
|
+
canAddMilestone && /* @__PURE__ */ jsx(
|
|
2285
|
+
"button",
|
|
2286
|
+
{
|
|
2287
|
+
type: "button",
|
|
2288
|
+
onClick: () => {
|
|
2289
|
+
setShowMilestoneForm((v) => !v);
|
|
2290
|
+
setMilestoneError(null);
|
|
2291
|
+
},
|
|
2292
|
+
"aria-label": L.addMilestone,
|
|
2293
|
+
"aria-expanded": showMilestoneForm,
|
|
2294
|
+
title: L.addMilestone,
|
|
2295
|
+
className: "flex h-6 w-6 items-center justify-center rounded-md border border-primary/40 text-primary hover:bg-primary/10",
|
|
2296
|
+
children: /* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5", "aria-hidden": "true" })
|
|
2297
|
+
}
|
|
2298
|
+
)
|
|
2205
2299
|
] }),
|
|
2206
|
-
|
|
2300
|
+
showMilestoneForm && canAddMilestone && /* @__PURE__ */ jsxs(
|
|
2301
|
+
"form",
|
|
2302
|
+
{
|
|
2303
|
+
onSubmit: submitMilestone,
|
|
2304
|
+
className: "mb-2 flex flex-wrap items-center gap-2",
|
|
2305
|
+
children: [
|
|
2306
|
+
/* @__PURE__ */ jsx(
|
|
2307
|
+
"input",
|
|
2308
|
+
{
|
|
2309
|
+
type: "text",
|
|
2310
|
+
value: milestoneName,
|
|
2311
|
+
onChange: (e) => setMilestoneName(e.target.value),
|
|
2312
|
+
placeholder: L.milestoneNamePlaceholder,
|
|
2313
|
+
"aria-label": L.milestoneNamePlaceholder,
|
|
2314
|
+
autoFocus: true,
|
|
2315
|
+
className: "h-8 min-w-40 flex-1 rounded-md border border-border bg-background px-2 text-xs text-foreground"
|
|
2316
|
+
}
|
|
2317
|
+
),
|
|
2318
|
+
/* @__PURE__ */ jsx(
|
|
2319
|
+
"input",
|
|
2320
|
+
{
|
|
2321
|
+
type: "date",
|
|
2322
|
+
value: milestoneDue,
|
|
2323
|
+
onChange: (e) => setMilestoneDue(e.target.value),
|
|
2324
|
+
"aria-label": L.dueDateLabel,
|
|
2325
|
+
className: "h-8 rounded-md border border-border bg-background px-2 text-xs text-foreground"
|
|
2326
|
+
}
|
|
2327
|
+
),
|
|
2328
|
+
/* @__PURE__ */ jsx(
|
|
2329
|
+
"button",
|
|
2330
|
+
{
|
|
2331
|
+
type: "submit",
|
|
2332
|
+
disabled: !milestoneName.trim() || creatingMilestone,
|
|
2333
|
+
className: "h-8 rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50",
|
|
2334
|
+
children: creatingMilestone ? L.creating : L.addMilestone
|
|
2335
|
+
}
|
|
2336
|
+
),
|
|
2337
|
+
/* @__PURE__ */ jsx(
|
|
2338
|
+
"button",
|
|
2339
|
+
{
|
|
2340
|
+
type: "button",
|
|
2341
|
+
onClick: () => {
|
|
2342
|
+
setShowMilestoneForm(false);
|
|
2343
|
+
setMilestoneError(null);
|
|
2344
|
+
},
|
|
2345
|
+
className: "h-8 rounded-md border border-border px-3 text-xs font-medium text-foreground hover:bg-muted/50",
|
|
2346
|
+
children: L.cancel
|
|
2347
|
+
}
|
|
2348
|
+
)
|
|
2349
|
+
]
|
|
2350
|
+
}
|
|
2351
|
+
),
|
|
2352
|
+
milestoneError && /* @__PURE__ */ jsx("p", { className: "mb-1 text-[11px] text-destructive", children: milestoneError }),
|
|
2353
|
+
milestones.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: milestones.map((m) => /* @__PURE__ */ jsx(MilestoneFlag, { milestone: m }, m.id)) })
|
|
2207
2354
|
] }),
|
|
2208
2355
|
mode === "week" ? /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-2", children: days.map((day) => {
|
|
2209
2356
|
const items = byDay.get(dayKey(day)) ?? [];
|
|
@@ -3342,6 +3489,7 @@ function TasksPageCore({
|
|
|
3342
3489
|
boardProjectId,
|
|
3343
3490
|
columns,
|
|
3344
3491
|
readonly,
|
|
3492
|
+
canCreateMilestone,
|
|
3345
3493
|
hiddenFields,
|
|
3346
3494
|
views,
|
|
3347
3495
|
defaultView = "board",
|
|
@@ -3539,7 +3687,9 @@ function TasksPageCore({
|
|
|
3539
3687
|
search,
|
|
3540
3688
|
assigneeId: mineAssignee,
|
|
3541
3689
|
resolveAssignee,
|
|
3542
|
-
onSelect: handleSelect
|
|
3690
|
+
onSelect: handleSelect,
|
|
3691
|
+
canCreateMilestone: canCreateMilestone ?? !readonly,
|
|
3692
|
+
milestoneProjectId: boardProjectId ?? projectId
|
|
3543
3693
|
}
|
|
3544
3694
|
),
|
|
3545
3695
|
showInlineDetail && /* @__PURE__ */ jsx("div", { className: "pb-6", children: detailView }),
|