rules.html 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <pstm-uri>/rules</pstm-uri>
  5. <pstm-template>main</pstm-template>
  6. </head>
  7. <body>
  8. <section>
  9. <div class="cluster cluster-between">
  10. <h1>Rules</h1>
  11. <!-- Goal 41 T9 (ux-notes expander fatigue): "New rule" hid
  12. behind a collapsed <details>. The primary action is now
  13. a persistent button opening a Spry dialog (the
  14. openAppDialog helper closes it on the action's
  15. notify). -->
  16. <button type="button" class="btn-primary"
  17. onclick="window.openAppDialog('rule-create-dialog')">+ New rule</button>
  18. </div>
  19. <p class="text-muted">Reusable instructions dispatched with every task that carries them —
  20. attach rules on the project and task pages.</p>
  21. <div stm-if="rules == null" class="page-loading" role="status" aria-label="Loading"><span class="spinner spinner-lg"></span></div>
  22. <div stm-if="rules != null">
  23. <div stm-for-rule-in="rules.rules" stm-key="rule.id" class="card">
  24. <!-- Goal 41 T9 (ux-notes rules): the Edit expander became
  25. the in-place editor (the data-long-form engine in
  26. app.js) — the edit half prefills from the slot's
  27. current values, so it edits what IS instead of a
  28. cold empty form. Delete left the row's face for a
  29. visually secondary danger control inside the
  30. confirm, inverting the old destructive-more-
  31. prominent-than-edit accident. -->
  32. <div data-long-form data-field="rule-row">
  33. <div class="card-header cluster cluster-between">
  34. <h3 stm-text="rule.name">name</h3>
  35. <button type="button" class="btn-ghost btn-sm" data-lf-toggle>Edit</button>
  36. </div>
  37. <div class="card-body" data-lf-view>
  38. <div class="md" stm-markdown="rule.body">body</div>
  39. <p class="text-muted">Created <span stm-text="rule.created_display">when</span></p>
  40. </div>
  41. <div class="card-body" data-lf-edit hidden>
  42. <!-- No data-lf-src here: these editors live INSIDE a
  43. stm-for loop, so no slot path can address the
  44. row. The textarea instead prefills from
  45. stm-text (textContent pre-fills a pristine
  46. textarea; this page re-renders only on its
  47. own actions, never on a pulse) and the input
  48. from stm-attribute.value. The lf engine's
  49. prefill pass simply finds no data-lf-src
  50. controls and leaves both as rendered. -->
  51. <form stm-action="rule.update" class="form-rows">
  52. <input type="hidden" name="rule_id" stm-attribute.value="rule.id">
  53. <div class="field"><label>Name</label>
  54. <input type="text" name="name"
  55. stm-attribute.value="rule.name"></div>
  56. <div class="field"><label>Body</label>
  57. <textarea name="body" rows="4"
  58. stm-text="rule.body">body</textarea></div>
  59. <div class="cluster">
  60. <button type="submit" class="btn-primary">Save</button>
  61. <button type="button" class="btn-ghost" data-lf-toggle>Cancel</button>
  62. </div>
  63. </form>
  64. </div>
  65. </div>
  66. <div class="card-body">
  67. <!-- Goal 41 T9 (ux-notes rules): the blast radius —
  68. where this rule is attached. A delete here
  69. detaches it from every listed project and
  70. task; naming them makes the confirm honest. -->
  71. <p stm-if="rule.attachments.length > 0" class="text-muted">Attached to
  72. <span stm-for-attachment-in="rule.attachments">
  73. <a stm-if="attachment.kind == 'project'"
  74. stm-attribute.href="'/projects/' + attachment.id"
  75. stm-text="attachment.label">project</a>
  76. <a stm-if="attachment.kind == 'task'"
  77. stm-attribute.href="'/tasks/' + attachment.id"
  78. stm-text="'#' + attachment.id + ' ' + attachment.label">task</a>
  79. </span>
  80. </p>
  81. <p stm-if="rule.attachments.length == 0" class="text-muted">Not attached
  82. anywhere — deleting it changes no dispatch.</p>
  83. <button type="button" class="btn-ghost btn-sm"
  84. stm-action="rule.delete"
  85. stm-confirm="Delete this rule everywhere? It detaches from every project and task listed above.">Delete rule…</button>
  86. </div>
  87. </div>
  88. <p stm-if="rules.rules.length == 0" class="text-muted">No rules yet.</p>
  89. </div>
  90. <dialog id="rule-create-dialog" class="dialog-sm">
  91. <div class="dialog-titlebar">
  92. <p class="dialog-title">New rule</p>
  93. <button type="button" class="dialog-close" aria-label="Close"
  94. onclick="window.closeAppDialog('rule-create-dialog')">×</button>
  95. </div>
  96. <form stm-action="rules.create">
  97. <div class="dialog-body form-rows">
  98. <div class="field"><label for="rule-new-name">Name</label>
  99. <input type="text" id="rule-new-name" name="name" required
  100. placeholder="Use Invercargill"></div>
  101. <div class="field"><label for="rule-new-body">Body</label>
  102. <textarea name="body" id="rule-new-body" rows="3" required
  103. placeholder="Never use libgee; use Invercargill enumerables."></textarea></div>
  104. </div>
  105. <div class="dialog-footer">
  106. <button type="button" class="btn-ghost"
  107. onclick="window.closeAppDialog('rule-create-dialog')">Cancel</button>
  108. <button type="submit" class="btn-primary">Create rule</button>
  109. </div>
  110. </form>
  111. </dialog>
  112. </section>
  113. </body>
  114. </html>