Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for semi-controlled fields #915

Open
stephenh opened this issue Dec 16, 2023 · 0 comments
Open

Support for semi-controlled fields #915

stephenh opened this issue Dec 16, 2023 · 0 comments

Comments

@stephenh
Copy link
Collaborator

stephenh commented Dec 16, 2023

We sometimes have fields that are half user-controlled and half system-controlled.

Because they are not fully system-controlled, they cannot be persisted derived fields.

But we'd still like an abstraction to represent them, because now the current approach is to leave them as dumb fields, and just have hooks poke them at various times.


Examples

/** Mark tradePartnerStatus=CompletedJob when a task is completed. */
config.beforeFlush((task) => {
  if (task.changes.status.hasChanged && task.isComplete) {
    task.tradePartnerStatus = TradePartnerTaskStatus.CompletedJob;
  }
});
config.beforeFlush((task) => {
  if (task.changes.globalTask.hasChanged && task.globalTask.isSet) {
    task.name = undefined;
  }
});
// if the task tradPartner has just changed and there are other signed commitments then update the tradePartner to the first signed commitment
config.beforeFlush(async (task) => {
  if (task.changes.tradePartner.hasUpdated && !task.tradePartner.isSet) {
    await task.assignCommitmentTrade();
  }
});
// Update signedOn when the BCR is signed
config.beforeFlush((bcr) => {
  if (bcr.changes.status.hasChanged && bcr.isSigned) {
    bcr.signedOn = new Date();
  }
});

Ideas

  • joist-config.json marks a field as derived: "semi"
readonly name = hasSemiDerivedField("name", config => {
  config.on("globalTask", task => {
    task.name = undefined
  },
});
readonly name = hasSemiDerivedField("name", 
  {
    condition: { status: Complete }, 
    then: () => {
      task.tradePartnerStatus = TradePartnerTaskStatus.CompletedJob;
    }
  },
  // or other conditions that watch other variables
  {
    condition: "otherField",
    then: (t) => task.otherField.get,
  }
);
  • A new method on the config API, similar to adding rules/hooks
config.addFieldReaction(
  // the field to update
  "signedOn", 
  // the reactive graph -- with conditions?
  { status: BidContractRevision.Signed },
  () => new Date()
);

Questions:

  • How do we avoid re-invoking them too frequently?
  • Transitions like draft -> active are easier to record has having "happened" and not redo
  • Should we split fields that flip from "100% manual to 100% derived", i.e. ProjectItem.quantity / etc., into a separate abstraction? That is a special subset of semi-controlled fields.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant