@outbuild-company/schedule-core 1.25.0 → 1.26.0

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.cjs CHANGED
@@ -630,17 +630,19 @@ function createActivitiesApi(engine) {
630
630
  }
631
631
  function createCellsApi(engine) {
632
632
  return {
633
- copy: (activityId, column, context = {}) => engine.dispatch({
633
+ copy: (activityId, column, copiedText, context = {}) => engine.dispatch({
634
634
  ...context,
635
635
  kind: DISPATCH_ACTION_KIND.CELL_COPY,
636
636
  activityId,
637
- column
637
+ column,
638
+ ...copiedText === void 0 ? {} : { copiedText }
638
639
  }),
639
- paste: (activityIds, column, context = {}) => engine.dispatch({
640
+ paste: (activityIds, column, clipboardText, context = {}) => engine.dispatch({
640
641
  ...context,
641
642
  kind: DISPATCH_ACTION_KIND.CELL_PASTE_COPIED,
642
643
  activityIds,
643
- column
644
+ column,
645
+ ...clipboardText === void 0 ? {} : { clipboardText }
644
646
  }),
645
647
  clearClipboard: (context = {}) => engine.dispatch({
646
648
  ...context,
@@ -957,6 +959,7 @@ var REJECTION_REASON = {
957
959
  NO_ACTIVITY_SELECTION: "no_activity_selection",
958
960
  CLIPBOARD_EMPTY: "clipboard_empty",
959
961
  CLIPBOARD_SNAPSHOT_INVALID: "clipboard_snapshot_invalid",
962
+ CELL_PASTE_COLUMN_MISMATCH: "cell_paste_column_mismatch",
960
963
  ACTIVITY_PASTE_INVARIANT_FAILED: "activity_paste_invariant_failed",
961
964
  SOLE_SCHEDULE_ROOT: "sole_schedule_root",
962
965
  ANCHOR_SIBLING_CONFLICT: "anchor_sibling_conflict",
@@ -19012,7 +19015,12 @@ function dispatchCellCopy(action, deps) {
19012
19015
  return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
19013
19016
  }
19014
19017
  const raw = action.column === COLUMN.DURATION ? canonicalValue / deps.hoursPerDay : cloneDomainValue(canonicalValue);
19015
- deps.clipboard.value = { kind: CELL_CLIPBOARD_KIND.FIELD, raw };
19018
+ deps.clipboard.value = {
19019
+ kind: CELL_CLIPBOARD_KIND.FIELD,
19020
+ raw,
19021
+ sourceColumn: action.column,
19022
+ text: action.copiedText ?? null
19023
+ };
19016
19024
  return emptyChangeSet(action);
19017
19025
  }
19018
19026
  function dispatchCellClipboardClear(action, clipboard) {
@@ -19021,6 +19029,39 @@ function dispatchCellClipboardClear(action, clipboard) {
19021
19029
  }
19022
19030
 
19023
19031
  // src/cell-copy-paste/paste.ts
19032
+ var RESTRICTED_CELL_COLUMNS = /* @__PURE__ */ new Set([
19033
+ COLUMN.TAGS,
19034
+ COLUMN.RESPONSABLES,
19035
+ COLUMN.SUBCONTRACT_ID,
19036
+ COLUMN.CONSTRAINT_TYPE,
19037
+ COLUMN.CALENDAR_ID
19038
+ ]);
19039
+ function isIncompatibleCellPaste(sourceColumn, targetColumn) {
19040
+ if (sourceColumn === targetColumn) return false;
19041
+ return RESTRICTED_CELL_COLUMNS.has(sourceColumn) || RESTRICTED_CELL_COLUMNS.has(targetColumn);
19042
+ }
19043
+ function resolveExternalPasteText(stashedField, clipboardText) {
19044
+ if (clipboardText === void 0) return null;
19045
+ const rawIsTrustworthy = stashedField !== null && (stashedField.text === null || stashedField.text === clipboardText);
19046
+ return rawIsTrustworthy ? null : clipboardText;
19047
+ }
19048
+ function resolveFieldPasteValue(clipboard, column, clipboardText) {
19049
+ const stashedField = clipboard !== null && clipboard.kind === CELL_CLIPBOARD_KIND.FIELD ? clipboard : null;
19050
+ const externalText = resolveExternalPasteText(stashedField, clipboardText);
19051
+ if (externalText !== null) {
19052
+ return { ok: true, newValue: externalText };
19053
+ }
19054
+ if (clipboard !== null && clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
19055
+ return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
19056
+ }
19057
+ if (stashedField === null) {
19058
+ return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
19059
+ }
19060
+ if (isIncompatibleCellPaste(stashedField.sourceColumn, column)) {
19061
+ return { ok: false, reason: REJECTION_REASON.CELL_PASTE_COLUMN_MISMATCH };
19062
+ }
19063
+ return { ok: true, newValue: stashedField.raw };
19064
+ }
19024
19065
  function toDiffPlaceholder(activityId) {
19025
19066
  return String(activityId);
19026
19067
  }
@@ -19053,11 +19094,45 @@ function linkOperationsForTarget(targetActivityId, isPredecessors, clipboard, de
19053
19094
  });
19054
19095
  return diff.operations;
19055
19096
  }
19056
- async function dispatchCellPasteCopied(action, options, deps) {
19057
- const clipboard = deps.cellClipboard.value;
19097
+ async function dispatchCellPasteLinkColumn(action, clipboard, options, deps) {
19058
19098
  if (clipboard === null) {
19059
19099
  return { ok: false, reason: REJECTION_REASON.CLIPBOARD_EMPTY };
19060
19100
  }
19101
+ if (clipboard.kind !== CELL_CLIPBOARD_KIND.LINKS) {
19102
+ return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
19103
+ }
19104
+ const hasSelfReference = action.activityIds.some(
19105
+ (activityId) => clipboard.specs.some(
19106
+ (spec) => String(spec.otherActivityId) === String(activityId)
19107
+ )
19108
+ );
19109
+ if (hasSelfReference) {
19110
+ return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
19111
+ }
19112
+ const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
19113
+ const operations = action.activityIds.flatMap(
19114
+ (activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
19115
+ );
19116
+ const createEntries = operations.filter(
19117
+ (operation) => operation.kind === LINK_OPERATION_KIND.CREATE
19118
+ ).map((operation) => ({
19119
+ operation,
19120
+ linkId: deps.linkIdGen.next()
19121
+ }));
19122
+ const creation = validateLinkCreateBatch(createEntries, {
19123
+ port: deps.adapter,
19124
+ rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
19125
+ });
19126
+ if (!creation.applied) {
19127
+ return {
19128
+ ok: false,
19129
+ reason: creation.rejected ?? REJECTION_REASON.INVALID
19130
+ };
19131
+ }
19132
+ return dispatchLinkBatch(operations, action, options, deps);
19133
+ }
19134
+ async function dispatchCellPasteCopied(action, options, deps) {
19135
+ const clipboard = deps.cellClipboard.value;
19061
19136
  if (action.activityIds.length === 0) {
19062
19137
  return { ok: false, reason: REJECTION_REASON.ACTIVITY_IDS_EMPTY };
19063
19138
  }
@@ -19068,53 +19143,25 @@ async function dispatchCellPasteCopied(action, options, deps) {
19068
19143
  return { ok: false, reason: REJECTION_REASON.ACTIVITY_NOT_FOUND };
19069
19144
  }
19070
19145
  if (action.column === COLUMN.CUSTOM_PREDECESSORS || action.column === COLUMN.CUSTOM_SUCESSORS) {
19071
- if (clipboard.kind !== CELL_CLIPBOARD_KIND.LINKS) {
19072
- return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
19073
- }
19074
- const hasSelfReference = action.activityIds.some(
19075
- (activityId) => clipboard.specs.some(
19076
- (spec) => String(spec.otherActivityId) === String(activityId)
19077
- )
19078
- );
19079
- if (hasSelfReference) {
19080
- return { ok: false, reason: LINK_REJECTION_REASON.SELF_LINK };
19081
- }
19082
- const isPredecessors = action.column === COLUMN.CUSTOM_PREDECESSORS;
19083
- const operations = action.activityIds.flatMap(
19084
- (activityId) => linkOperationsForTarget(activityId, isPredecessors, clipboard, deps)
19085
- );
19086
- const createEntries = operations.filter(
19087
- (operation) => operation.kind === LINK_OPERATION_KIND.CREATE
19088
- ).map((operation) => ({
19089
- operation,
19090
- linkId: deps.linkIdGen.next()
19091
- }));
19092
- const creation = validateLinkCreateBatch(createEntries, {
19093
- port: deps.adapter,
19094
- rejectParentLinkMutations: options.rejectParentLinkMutations ?? false
19095
- });
19096
- if (!creation.applied) {
19097
- return {
19098
- ok: false,
19099
- reason: creation.rejected ?? REJECTION_REASON.INVALID
19100
- };
19101
- }
19102
- return dispatchLinkBatch(operations, action, options, deps);
19103
- }
19104
- if (clipboard.kind !== CELL_CLIPBOARD_KIND.FIELD) {
19105
- return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
19146
+ return dispatchCellPasteLinkColumn(action, clipboard, options, deps);
19106
19147
  }
19107
19148
  if (!findPipelineForColumn(action.column)) {
19108
19149
  return { ok: false, reason: REJECTION_REASON.NO_PIPELINE_FOR_COLUMN };
19109
19150
  }
19110
19151
  const column = action.column;
19152
+ const resolution = resolveFieldPasteValue(
19153
+ clipboard,
19154
+ column,
19155
+ action.clipboardText
19156
+ );
19157
+ if (!resolution.ok) return resolution;
19111
19158
  const result = await dispatchBulkEdit(
19112
19159
  {
19113
19160
  kind: DISPATCH_ACTION_KIND.BULK_EDIT,
19114
19161
  edits: action.activityIds.map((activityId) => ({
19115
19162
  activityId,
19116
19163
  column,
19117
- newValue: clipboard.raw
19164
+ newValue: resolution.newValue
19118
19165
  })),
19119
19166
  ...action.eventSource === void 0 ? {} : { eventSource: action.eventSource }
19120
19167
  },