dawlad-paperclip-direction 0.3.2 → 0.3.3

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/manifest.js CHANGED
@@ -11,7 +11,7 @@ var route = (routeKey, method, path) => ({
11
11
  var manifest = {
12
12
  id: "dawlad.direction",
13
13
  apiVersion: 1,
14
- version: "0.3.2",
14
+ version: "0.3.3",
15
15
  displayName: "Direction",
16
16
  description: "Horizon, campaigns, milestones and one queue of decisions: where Dawlad is heading and what's in the way.",
17
17
  author: "Aly Solamon",
package/dist/ui/index.js CHANGED
@@ -184,6 +184,11 @@ html:has([data-dx-page="decisions"]) ol[data-slot="breadcrumb-list"]:has(a[href$
184
184
  .dx-props-g { display: grid; grid-template-columns: 96px minmax(0, 1fr); row-gap: 12px; column-gap: 12px; font-size: 13.5px; align-items: center; padding-bottom: 10px; border-bottom: 1px solid var(--dx-line); }
185
185
  .dx-props-g .k { color: var(--dx-muted); }
186
186
  .dx-props-g .v { min-width: 0; overflow-wrap: anywhere; }
187
+ .dx-pv { border: 1px solid transparent; background: transparent; color: var(--dx-fg); font: inherit; font-size: 13.5px; padding: 3px 6px; margin-left: -7px; border-radius: 6px; max-width: 100%; cursor: pointer; color-scheme: inherit; }
188
+ .dx-pv:hover, .dx-pv:focus { border-color: var(--dx-line); background: var(--dx-soft); outline: none; }
189
+ .dx-pv option { background: var(--dx-card); color: var(--dx-fg); }
190
+ .dx-pv.num { width: 72px; cursor: text; }
191
+ .dx-busy { opacity: .55; pointer-events: none; }
187
192
  .dx-plist { display: grid; gap: 2px; }
188
193
  .dx-plist .r { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; border: 0; background: transparent; color: var(--dx-fg); padding: 7px 6px; border-radius: 6px; cursor: pointer; font-size: 13.5px; }
189
194
  .dx-plist .r:hover, .dx-plist .r:focus-visible { background: var(--dx-soft2); outline: none; }
@@ -2353,7 +2358,7 @@ function CampaignPage({ companyId, goalId, tab, m, query }) {
2353
2358
  tab === "connected" && /* @__PURE__ */ jsx7(ConnectedTab, { d: data, extra }),
2354
2359
  tab === "activity" && /* @__PURE__ */ jsx7(ActivityTab, { d: data })
2355
2360
  ] }),
2356
- pane ? /* @__PURE__ */ jsx7(CampaignPane, { d: data, extra, onClose: () => setPane(false) }) : /* @__PURE__ */ jsxs7("aside", { className: "dx-pane-rail", children: [
2361
+ pane ? /* @__PURE__ */ jsx7(CampaignPane, { d: data, extra, m, companyId, refresh, onClose: () => setPane(false) }) : /* @__PURE__ */ jsxs7("aside", { className: "dx-pane-rail", children: [
2357
2362
  /* @__PURE__ */ jsx7("button", { className: "dx-icon", "aria-label": "Show the properties panel", title: "Properties and everything linked", onClick: () => setPane(true), children: Ico.doc }),
2358
2363
  /* @__PURE__ */ jsx7("span", { className: "dx-pane-rail-t", onClick: () => setPane(true), children: "Properties" })
2359
2364
  ] })
@@ -2784,7 +2789,7 @@ function useHostConnected(companyId, d) {
2784
2789
  }, [key]);
2785
2790
  return out;
2786
2791
  }
2787
- function CampaignPane({ d, extra, onClose }) {
2792
+ function CampaignPane({ d, extra, m, companyId, refresh, onClose }) {
2788
2793
  const go = useGo("direction");
2789
2794
  const groups = [
2790
2795
  {
@@ -2894,44 +2899,120 @@ function CampaignPane({ d, extra, onClose }) {
2894
2899
  /* @__PURE__ */ jsx7("span", { style: { flex: 1 } }),
2895
2900
  /* @__PURE__ */ jsx7("button", { className: "dx-icon", "aria-label": "Hide the panel", title: "Hide the panel", onClick: onClose, children: Ico.x })
2896
2901
  ] }),
2897
- /* @__PURE__ */ jsx7("div", { className: "dx-pane-body", children: active === "props" ? /* @__PURE__ */ jsx7(CampaignProps, { d, groups, onOpen: pick }) : cur ? /* @__PURE__ */ jsx7(ConnList, { g: cur, onItem: openItem }) : /* @__PURE__ */ jsxs7("div", { className: "dx-pane-empty", children: [
2902
+ /* @__PURE__ */ jsx7("div", { className: "dx-pane-body", children: active === "props" ? /* @__PURE__ */ jsx7(CampaignProps, { d, m, companyId, refresh, groups, onOpen: pick }) : cur ? /* @__PURE__ */ jsx7(ConnList, { g: cur, onItem: openItem }) : /* @__PURE__ */ jsxs7("div", { className: "dx-pane-empty", children: [
2898
2903
  /* @__PURE__ */ jsx7("b", { children: "Nothing is open." }),
2899
2904
  /* @__PURE__ */ jsx7("span", { className: "dx-muted dx-small", children: "Use + to open the properties or anything linked to this campaign." })
2900
2905
  ] }) })
2901
2906
  ] });
2902
2907
  }
2903
- function CampaignProps({ d, groups, onOpen }) {
2908
+ function useAgents(companyId) {
2909
+ const [list, setList] = useState6([]);
2910
+ useEffect3(() => {
2911
+ let live = true;
2912
+ fetch(`/api/companies/${companyId}/agents`, { credentials: "same-origin" }).then((r) => r.ok ? r.json() : []).then((a) => {
2913
+ if (live) setList((Array.isArray(a) ? a : []).filter((x) => x.status !== "terminated").map((x) => ({ id: x.id, name: x.name, title: x.title ?? null })));
2914
+ }).catch(() => {
2915
+ });
2916
+ return () => {
2917
+ live = false;
2918
+ };
2919
+ }, [companyId]);
2920
+ return list;
2921
+ }
2922
+ function CampaignProps({ d, m, companyId, refresh, groups, onOpen }) {
2904
2923
  const c = d.campaign;
2905
- const row = (k, v) => /* @__PURE__ */ jsxs7(Fragment4, { children: [
2924
+ const set = usePluginAction("set-campaign");
2925
+ const agents = useAgents(companyId);
2926
+ const [busy, setBusy] = useState6(null);
2927
+ const [err, setErr] = useState6(null);
2928
+ const [mins, setMins] = useState6(c.alyMinutes != null ? String(c.alyMinutes) : "");
2929
+ useEffect3(() => setMins(c.alyMinutes != null ? String(c.alyMinutes) : ""), [c.alyMinutes]);
2930
+ const save = async (field, patch) => {
2931
+ setBusy(field);
2932
+ setErr(null);
2933
+ try {
2934
+ await set({ companyId, goalId: c.goalId, ...patch });
2935
+ refresh();
2936
+ } catch (e) {
2937
+ setErr(e.message);
2938
+ } finally {
2939
+ setBusy(null);
2940
+ }
2941
+ };
2942
+ const row = (k, v, field) => /* @__PURE__ */ jsxs7(Fragment4, { children: [
2906
2943
  /* @__PURE__ */ jsx7("span", { className: "k", children: k }),
2907
- /* @__PURE__ */ jsx7("span", { className: "v", children: v })
2944
+ /* @__PURE__ */ jsx7("span", { className: `v${busy === field ? " dx-busy" : ""}`, children: v })
2908
2945
  ] });
2946
+ const lead = c.owner.kind === "agent" ? c.owner.id ?? "" : "";
2909
2947
  return /* @__PURE__ */ jsxs7("div", { className: "dx-props", children: [
2910
2948
  /* @__PURE__ */ jsx7("div", { className: "dx-props-h", children: "Direction" }),
2911
2949
  /* @__PURE__ */ jsxs7("div", { className: "dx-props-g", children: [
2912
- row("Lead", /* @__PURE__ */ jsxs7("span", { className: "dx-row", children: [
2913
- /* @__PURE__ */ jsx7(Avatar, { who: c.owner }),
2914
- c.owner.name,
2915
- c.owner.title ? /* @__PURE__ */ jsxs7("span", { className: "dx-muted", children: [
2916
- "\xB7 ",
2917
- c.owner.title
2918
- ] }) : null
2919
- ] })),
2920
- row("Team", c.team?.name ?? /* @__PURE__ */ jsx7("span", { className: "dx-faint", children: "no team" })),
2921
- row("Serves", c.partName ?? /* @__PURE__ */ jsx7("span", { className: "dx-faint", children: "not placed" })),
2922
- row("Rank", /* @__PURE__ */ jsxs7("span", { className: "dx-row", children: [
2923
- c.rankLabel ? /* @__PURE__ */ jsx7("span", { className: "dx-pill solid", children: c.rankLabel }) : null,
2924
- /* @__PURE__ */ jsx7("span", { className: "dx-muted", children: c.state })
2925
- ] })),
2950
+ row("Lead", /* @__PURE__ */ jsxs7("select", { className: "dx-pv", "aria-label": "Lead", value: lead, onChange: (e) => save("lead", { leadAgentId: e.target.value || null }), children: [
2951
+ /* @__PURE__ */ jsx7("option", { value: "", children: "No lead" }),
2952
+ agents.map((a) => /* @__PURE__ */ jsxs7("option", { value: a.id, children: [
2953
+ a.name,
2954
+ a.title ? ` \xB7 ${a.title}` : ""
2955
+ ] }, a.id))
2956
+ ] }), "lead"),
2957
+ row("Team", /* @__PURE__ */ jsxs7("select", { className: "dx-pv", "aria-label": "Team", value: c.team?.goalId ?? "", onChange: (e) => e.target.value && save("team", { teamGoalId: e.target.value }), children: [
2958
+ !c.team && /* @__PURE__ */ jsx7("option", { value: "", children: "No team" }),
2959
+ m.teams.map((t) => /* @__PURE__ */ jsx7("option", { value: t.goalId, children: t.name }, t.goalId))
2960
+ ] }), "team"),
2961
+ row("Serves", /* @__PURE__ */ jsxs7("select", { className: "dx-pv", "aria-label": "Serves", value: c.partId ?? "", onChange: (e) => save("part", { partId: e.target.value || null }), children: [
2962
+ /* @__PURE__ */ jsx7("option", { value: "", children: "Not placed" }),
2963
+ m.horizon.parts.map((p) => /* @__PURE__ */ jsx7("option", { value: p.id, children: p.name }, p.id))
2964
+ ] }), "part"),
2965
+ row("Order", /* @__PURE__ */ jsxs7("span", { className: "dx-row", style: { gap: 4 }, children: [
2966
+ /* @__PURE__ */ jsxs7("select", { className: "dx-pv", "aria-label": "Order", value: c.rankLabel ?? "", onChange: (e) => save("rank", { rankLabel: e.target.value || null }), children: [
2967
+ /* @__PURE__ */ jsx7("option", { value: "", children: "Not ranked" }),
2968
+ /* @__PURE__ */ jsx7("option", { value: "Now", children: "Now" }),
2969
+ /* @__PURE__ */ jsx7("option", { value: "Next", children: "Next" }),
2970
+ /* @__PURE__ */ jsx7("option", { value: "Later", children: "Later" })
2971
+ ] }),
2972
+ /* @__PURE__ */ jsxs7("select", { className: "dx-pv", "aria-label": "Focus or parked", value: c.state, onChange: (e) => save("rank", { state: e.target.value }), children: [
2973
+ /* @__PURE__ */ jsx7("option", { value: "focus", children: "focus" }),
2974
+ /* @__PURE__ */ jsx7("option", { value: "parked", children: "parked" })
2975
+ ] })
2976
+ ] }), "rank"),
2926
2977
  row("Health", /* @__PURE__ */ jsx7(HealthPill, { h: c.health }))
2927
2978
  ] }),
2928
2979
  /* @__PURE__ */ jsx7("div", { className: "dx-props-h", children: "Dates" }),
2929
2980
  /* @__PURE__ */ jsxs7("div", { className: "dx-props-g", children: [
2930
- row("Start", c.plannedStart ? fmt(c.plannedStart) : /* @__PURE__ */ jsx7("span", { className: "dx-faint", children: "not set" })),
2931
- row("Finish", fmt(c.forecastFinish ?? c.plannedFinish)),
2981
+ row("Start", /* @__PURE__ */ jsx7("input", { className: "dx-pv", type: "date", "aria-label": "Start", value: c.plannedStart ?? "", onChange: (e) => save("start", { plannedStart: e.target.value || null }) }), "start"),
2982
+ row("Finish", /* @__PURE__ */ jsxs7("span", { className: "dx-row", style: { gap: 6, flexWrap: "wrap" }, children: [
2983
+ /* @__PURE__ */ jsx7("input", { className: "dx-pv", type: "date", "aria-label": "Planned finish", value: c.plannedFinish ?? "", onChange: (e) => save("finish", { plannedFinish: e.target.value || null }) }),
2984
+ c.forecastFinish && c.forecastFinish !== c.plannedFinish && /* @__PURE__ */ jsxs7("span", { className: "dx-muted dx-xs", children: [
2985
+ "forecast ",
2986
+ fmt(c.forecastFinish)
2987
+ ] })
2988
+ ] }), "finish"),
2932
2989
  row("Plan was", /* @__PURE__ */ jsx7("span", { className: "dx-muted", children: fmt(c.planFinish ?? c.plannedFinish) })),
2933
- row("Review", c.reviewDate ? fmt(c.reviewDate) : /* @__PURE__ */ jsx7("span", { className: "dx-faint", children: "not set" })),
2934
- row("Your time", c.alyMinutes != null ? `${c.alyMinutes} min a week` : /* @__PURE__ */ jsx7("span", { className: "dx-faint", children: "not set" }))
2990
+ row("Review", /* @__PURE__ */ jsx7("input", { className: "dx-pv", type: "date", "aria-label": "Review date", value: c.reviewDate ?? "", onChange: (e) => save("review", { reviewDate: e.target.value || null }) }), "review"),
2991
+ row("Your time", /* @__PURE__ */ jsxs7("span", { className: "dx-row", style: { gap: 6 }, children: [
2992
+ /* @__PURE__ */ jsx7(
2993
+ "input",
2994
+ {
2995
+ className: "dx-pv num",
2996
+ type: "number",
2997
+ min: 0,
2998
+ step: 5,
2999
+ "aria-label": "Your minutes a week",
3000
+ placeholder: "not set",
3001
+ value: mins,
3002
+ onChange: (e) => setMins(e.target.value),
3003
+ onBlur: () => {
3004
+ const v = mins.trim() === "" ? null : Number(mins);
3005
+ if (v !== c.alyMinutes) save("mins", { alyMinutes: v });
3006
+ },
3007
+ onKeyDown: (e) => e.key === "Enter" && e.target.blur()
3008
+ }
3009
+ ),
3010
+ /* @__PURE__ */ jsx7("span", { className: "dx-muted dx-small", children: "min a week" })
3011
+ ] }), "mins")
3012
+ ] }),
3013
+ err && /* @__PURE__ */ jsxs7("div", { className: "dx-err dx-small", children: [
3014
+ "Couldn't save: ",
3015
+ err
2935
3016
  ] }),
2936
3017
  /* @__PURE__ */ jsx7("div", { className: "dx-props-h", children: "Linked" }),
2937
3018
  /* @__PURE__ */ jsx7("div", { className: "dx-plist", children: groups.map((g) => /* @__PURE__ */ jsxs7("button", { className: "r", onClick: () => onOpen(g.kind), children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dawlad-paperclip-direction",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "type": "module",
5
5
  "description": "Paperclip plugin: Horizon, campaigns and milestones (Direction page) for Da Applied AI Lab.",
6
6
  "paperclipPlugin": {