issue-pane 2.4.9 → 2.4.10-0fa14c64

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/.eslintrc CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
+ "root": true,
2
3
  "env": {
3
4
  "browser": true,
4
5
  "es6": true,
5
6
  "node": true
6
7
  },
7
- "extends": "standard",
8
8
  "globals": {
9
9
  "Atomics": "readonly",
10
10
  "SharedArrayBuffer": "readonly"
@@ -14,5 +14,6 @@
14
14
  "argsIgnorePattern": "^_",
15
15
  "varsIgnorePattern": "^_"
16
16
  }]
17
- }
17
+ },
18
+ "extends": ["eslint:recommended", "plugin:import/recommended"]
18
19
  }
@@ -24,7 +24,36 @@ jobs:
24
24
  uses: actions/setup-node@v1
25
25
  with:
26
26
  node-version: ${{ matrix.node-version }}
27
- - run: npm install -g npm # for issues with executables on npm 7
28
27
  - run: npm ci
28
+ - run: npm run lint --if-present
29
29
  - run: npm test
30
- - run: npm run build
30
+ - run: npm run build --if-present
31
+ - name: Save build
32
+ if: matrix.node-version == '14.x'
33
+ uses: actions/upload-artifact@v2
34
+ with:
35
+ name: build
36
+ path: |
37
+ .
38
+ !node_modules
39
+ retention-days: 1
40
+ npm-publish-build:
41
+ needs: build
42
+ runs-on: ubuntu-latest
43
+ steps:
44
+ - uses: actions/download-artifact@v2
45
+ with:
46
+ name: build
47
+ - uses: actions/setup-node@v1
48
+ with:
49
+ node-version: 14.x
50
+ - uses: rlespinasse/github-slug-action@v3.x
51
+ - name: Append commit hash to package version
52
+ run: 'sed -i -E "s/(\"version\": *\"[^\"]+)/\1-${GITHUB_SHA_SHORT}/" package.json'
53
+ - name: Disable pre- and post-publish actions
54
+ run: 'sed -i -E "s/\"((pre|post)publish)/\"ignore:\1/" package.json'
55
+ - uses: JS-DevTools/npm-publish@v1
56
+ with:
57
+ token: ${{ secrets.NPM_TOKEN }}
58
+ tag: ${{ env.GITHUB_REF_SLUG }}
59
+
package/.nvmrc CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/LICENSE.md CHANGED
File without changes
package/Makefile CHANGED
File without changes
package/README.md CHANGED
File without changes
package/board.js CHANGED
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import * as UI from 'solid-ui'
14
- const kb = UI.store
14
+ import { store } from 'solid-logic'
15
15
  const ns = UI.ns
16
16
  const $rdf = UI.rdf
17
17
 
@@ -38,7 +38,7 @@ export function board (dom, columnValues, renderItem, options) {
38
38
  function droppedURIHandler (uris) {
39
39
  uris.forEach(function (u) {
40
40
  console.log('Dropped on column: ' + u)
41
- const item = kb.sym(u)
41
+ const item = store.sym(u)
42
42
  options.columnDropHandler(item, x)
43
43
  })
44
44
  }
@@ -54,19 +54,19 @@ export function board (dom, columnValues, renderItem, options) {
54
54
  function defaultRenderItem (item, category) {
55
55
  const card = dom.createElement('div')
56
56
  const table = card.appendChild(dom.createElement('table'))
57
- const classes = kb.each(item, ns.rdf('type'))
58
- const catColors = classes.map(cat => kb.any(cat, ns.ui('backgroundColor'))).filter(c => c)
57
+ const classes = store.each(item, ns.rdf('type'))
58
+ const catColors = classes.map(cat => store.any(cat, ns.ui('backgroundColor'))).filter(c => c)
59
59
 
60
60
  table.appendChild(UI.widgets.personTR(dom, null, item))
61
61
  table.subject = item
62
62
  table.style = 'margin: 1em;' // @@ use style.js
63
- const backgroundColor = catColors[0] || kb.any(category, ns.ui('backgroundColor'))
63
+ const backgroundColor = catColors[0] || store.any(category, ns.ui('backgroundColor'))
64
64
  card.style.backgroundColor = backgroundColor ? backgroundColor.value : '#fff'
65
65
  return card
66
66
  }
67
67
 
68
68
  function sortedBy (values, predicate, defaultSortValue, reverse) {
69
- const toBeSorted = values.map(x => [kb.any(x, predicate) || defaultSortValue, x])
69
+ const toBeSorted = values.map(x => [store.any(x, predicate) || defaultSortValue, x])
70
70
  toBeSorted.sort()
71
71
  if (reverse) toBeSorted.reverse() // @@ check
72
72
  return toBeSorted.map(pair => pair[1])
@@ -82,7 +82,7 @@ export function board (dom, columnValues, renderItem, options) {
82
82
  }
83
83
  for (let col = mainRow.firstChild; col; col = col.nextSibling) {
84
84
  const category = col.subject
85
- let items = kb.each(null, ns.rdf('type'), category)
85
+ let items = store.each(null, ns.rdf('type'), category)
86
86
  const sortBy = options.sortBy || ns.dct('created')
87
87
  if (options.filter) {
88
88
  items = items.filter(options.filter)
package/issue.js CHANGED
@@ -1,52 +1,65 @@
1
1
  // All the UI for a single issue, without store load or listening for changes
2
2
  //
3
- import { authn, icons, messageArea, ns, rdf, store, style, utils, widgets } from 'solid-ui'
3
+ import { icons, messageArea, ns, rdf, style, utils, widgets } from 'solid-ui'
4
+ import { authn, store } from 'solid-logic'
4
5
  import { newIssueForm } from './newIssue'
5
6
 
6
7
  const $rdf = rdf
7
- const kb = store
8
8
 
9
9
  const SET_MODIFIED_DATES = false
10
10
 
11
+ export const TASK_ICON = icons.iconBase + 'noun_17020_gray-tick.svg'
12
+ export const OPEN_TASK_ICON = icons.iconBase + 'noun_17020_sans-tick.svg'
13
+ export const CLOSED_TASK_ICON = icons.iconBase + 'noun_17020.svg'
14
+
11
15
  function complain (message, context) {
12
16
  console.warn(message)
13
17
  context.paneDiv.appendChild(widgets.errorMessageBlock(context.dom, message))
14
18
  }
15
19
 
20
+ export function isOpen (issue) {
21
+ const types = store.findTypeURIs(issue)
22
+ return !!types[ns.wf('Open').uri]
23
+ }
24
+
25
+ export function iconForIssue (issue) {
26
+ return isOpen(issue) ? TASK_ICON : CLOSED_TASK_ICON
27
+ }
16
28
  export function getState (issue, classification) {
17
- const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
18
- const states = kb.any(tracker, ns.wf('issueClass'))
29
+ const tracker = store.the(issue, ns.wf('tracker'), null, issue.doc())
30
+ const states = store.any(tracker, ns.wf('issueClass'))
19
31
  classification = classification || states
20
- const types = kb.each(issue, ns.rdf('type'))
21
- .filter(ty => kb.holds(ty, ns.rdfs('subClassOf'), classification))
32
+ const types = store.each(issue, ns.rdf('type'))
33
+ .filter(ty => store.holds(ty, ns.rdfs('subClassOf'), classification))
22
34
  if (types.length !== 1) {
23
- // const initialState = kb.any(tracker, ns.wf('initialState')) No do NOT default
35
+ // const initialState = store.any(tracker, ns.wf('initialState')) No do NOT default
24
36
  // if (initialState) return initialState
25
37
  throw new Error('Issue must have one type as state: ' + types.length)
26
38
  }
27
39
  return types[0]
28
40
  }
29
41
 
30
- export function renderIssueCard (issue, context) {
31
- function getBackgroundColor () {
32
- const classes = kb.each(issue, ns.rdf('type')) // @@ pick cats in order then state
33
- const catColors = classes.map(cat => kb.any(cat, ns.ui('backgroundColor'))).filter(c => !!c)
42
+ export function getBackgroundColorFromTypes (issue) {
43
+ const classes = store.each(issue, ns.rdf('type')) // @@ pick cats in order then state
44
+ const catColors = classes.map(cat => store.any(cat, ns.ui('backgroundColor'))).filter(c => !!c)
34
45
 
35
- if (catColors.length) return catColors[0].value // pick first one
36
- return null
37
- }
46
+ if (catColors.length) return catColors[0].value // pick first one
47
+ return null
48
+ }
49
+
50
+ export function renderIssueCard (issue, context) {
38
51
  function refresh () {
39
- const backgroundColor = getBackgroundColor() || 'white'
52
+ const backgroundColor = getBackgroundColorFromTypes(issue) || 'white'
40
53
  card.style.backgroundColor = backgroundColor
41
54
  editButton.style.backgroundColor = backgroundColor // Override white from style sheet
42
55
  }
43
56
  const dom = context.dom
44
- const uncategorized = !getBackgroundColor() // This is a suspect issue. Prompt to delete it
57
+ const uncategorized = !getBackgroundColorFromTypes(issue) // This is a suspect issue. Prompt to delete it
45
58
 
46
59
  const card = dom.createElement('div')
47
60
  const table = card.appendChild(dom.createElement('table'))
48
61
  table.style.width = '100%'
49
- const options = { draggable: false } // Let the baord make th ewhole card draggable
62
+ const options = { draggable: false } // Let the board make the whole card draggable
50
63
  table.appendChild(widgets.personTR(dom, null, issue, options))
51
64
  table.subject = issue
52
65
  card.style = 'border-radius: 0.4em; border: 0.05em solid grey; margin: 0.3em;'
@@ -66,7 +79,7 @@ export function renderIssueCard (issue, context) {
66
79
  if (uncategorized) {
67
80
  const deleteButton = widgets.deleteButtonWithCheck(dom, buttonsCell, 'issue', async function () { // noun?
68
81
  try {
69
- await kb.updater.update(kb.connectedStatements(issue))
82
+ await store.updater.update(store.connectedStatements(issue))
70
83
  } catch (err) {
71
84
  complain(`Unable to delete issue: ${err}`, context)
72
85
  }
@@ -100,18 +113,24 @@ export function exposeOverlay (subject, context) {
100
113
  overlay.firstChild.style.overflow = 'auto' // was scroll
101
114
  }
102
115
 
116
+ function renderSpacer (dom, backgroundColor) {
117
+ const spacer = dom.createElement('div')
118
+ spacer.setAttribute('style', 'height: 1em; margin: 0.5em;') // spacer and placeHolder
119
+ spacer.style.backgroundColor = backgroundColor // try that
120
+ return spacer
121
+ }
122
+
103
123
  export function renderIssue (issue, context) {
104
124
  // Don't bother changing the last modified dates of things: save time
105
- function setModifiedDate (subj, kb, doc) {
125
+ function setModifiedDate (subj, store, doc) {
106
126
  if (SET_MODIFIED_DATES) {
107
127
  if (!getOption(tracker, 'trackLastModified')) return
108
- let deletions = kb.statementsMatching(issue, ns.dct('modified'))
109
- deletions = deletions.concat(
110
- kb.statementsMatching(issue, ns.wf('modifiedBy'))
111
- )
128
+ const deletions = store.statementsMatching(issue, ns.dct('modified'))
129
+ .concat(store.statementsMatching(issue, ns.wf('modifiedBy'))
130
+ )
112
131
  const insertions = [$rdf.st(issue, ns.dct('modified'), new Date(), doc)]
113
132
  if (me) insertions.push($rdf.st(issue, ns.wf('modifiedBy'), me, doc))
114
- kb.updater.update(deletions, insertions, function (_uri, _ok, _body) {})
133
+ store.updater.update(deletions, insertions, function (_uri, _ok, _body) {})
115
134
  }
116
135
  }
117
136
 
@@ -123,7 +142,7 @@ export function renderIssue (issue, context) {
123
142
  return pre
124
143
  }
125
144
 
126
- const timestring = function () {
145
+ function timestring () {
127
146
  const now = new Date()
128
147
  return '' + now.getTime()
129
148
  // http://www.w3schools.com/jsref/jsref_obj_date.asp
@@ -144,50 +163,50 @@ export function renderIssue (issue, context) {
144
163
  }
145
164
  function getOption (tracker, option) {
146
165
  // eg 'allowSubIssues'
147
- const opt = kb.any(tracker, ns.ui(option))
166
+ const opt = store.any(tracker, ns.ui(option))
148
167
  return !!(opt && opt.value)
149
168
  }
150
169
 
151
170
  function setPaneStyle () {
152
- const types = kb.findTypeURIs(issue)
153
- let mystyle = 'padding: 0.5em 1.5em 1em 1.5em; '
154
- let backgroundColor = null
155
- for (const uri in types) {
156
- backgroundColor = kb.any(
157
- kb.sym(uri),
158
- kb.sym('http://www.w3.org/ns/ui#backgroundColor')
159
- )
160
- if (backgroundColor) break
161
- }
162
- backgroundColor = backgroundColor ? backgroundColor.value : '#eee' // default grey
163
- mystyle += 'background-color: ' + backgroundColor + '; '
171
+ const backgroundColor = getBackgroundColorFromTypes(issue) || '#eee' // default grey
172
+ const mystyle0 = 'padding: 0.5em 1.5em 1em 1.5em; border: 0.7em;'
173
+ const mystyle = mystyle0 + 'border-color: ' + backgroundColor + '; '
164
174
  issueDiv.setAttribute('style', mystyle)
175
+ issueDiv.style.backgroundColor = 'white'
165
176
  }
166
177
 
178
+ /// ////////////// Body of renderIssue
179
+
167
180
  const dom = context.dom
168
- const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
181
+ // eslint-disable-next-line no-use-before-define
182
+ const tracker = store.the(issue, ns.wf('tracker'), null, issue.doc())
169
183
  if (!tracker) throw new Error('No tracker')
170
- const stateStore = kb.any(tracker, ns.wf('stateStore'))
184
+ // eslint-disable-next-line no-use-before-define
185
+ const stateStore = store.any(tracker, ns.wf('stateStore'))
171
186
  const store = issue.doc()
172
187
 
173
188
  const issueDiv = dom.createElement('div')
174
- var me = authn.currentUser()
189
+ const me = authn.currentUser()
190
+ const backgroundColor = getBackgroundColorFromTypes(issue) || 'white'
175
191
 
176
192
  setPaneStyle()
177
193
 
178
194
  authn.checkUser() // kick off async operation
179
195
 
180
- const states = kb.any(tracker, ns.wf('issueClass'))
196
+ const iconButton = issueDiv.appendChild(widgets.button(dom, iconForIssue(issue)))
197
+ widgets.makeDraggable(iconButton, issue) // Drag me wherever you need to do stuff with this issue
198
+
199
+ const states = store.any(tracker, ns.wf('issueClass'))
181
200
  if (!states) { throw new Error('This tracker ' + tracker + ' has no issueClass') }
182
201
  const select = widgets.makeSelectForCategory(
183
202
  dom,
184
- kb,
203
+ store,
185
204
  issue,
186
205
  states,
187
206
  stateStore,
188
207
  function (ok, body) {
189
208
  if (ok) {
190
- setModifiedDate(store, kb, store)
209
+ setModifiedDate(store, store, store)
191
210
  widgets.refreshTree(issueDiv)
192
211
  } else {
193
212
  console.log('Failed to change state:\n' + body)
@@ -196,18 +215,18 @@ export function renderIssue (issue, context) {
196
215
  )
197
216
  issueDiv.appendChild(select)
198
217
 
199
- const cats = kb.each(tracker, ns.wf('issueCategory')) // zero or more
200
- for (let i = 0; i < cats.length; i++) {
218
+ const cats = store.each(tracker, ns.wf('issueCategory')) // zero or more
219
+ for (const cat of cats) {
201
220
  issueDiv.appendChild(
202
221
  widgets.makeSelectForCategory(
203
222
  dom,
204
- kb,
223
+ store,
205
224
  issue,
206
- cats[i],
225
+ cat,
207
226
  stateStore,
208
227
  function (ok, body) {
209
228
  if (ok) {
210
- setModifiedDate(store, kb, store)
229
+ setModifiedDate(store, store, store)
211
230
  widgets.refreshTree(issueDiv)
212
231
  } else {
213
232
  console.log('Failed to change category:\n' + body)
@@ -251,40 +270,26 @@ export function renderIssue (issue, context) {
251
270
  wf:Task :creationForm core:coreIsueForm .
252
271
  `
253
272
  const CORE_ISSUE_FORM = ns.wf('coreIsueForm')
254
- $rdf.parse(coreIssueFormText, kb, CORE_ISSUE_FORM.doc().uri, 'text/turtle')
255
- widgets.appendForm(
273
+ $rdf.parse(coreIssueFormText, store, CORE_ISSUE_FORM.doc().uri, 'text/turtle')
274
+ const form = widgets.appendForm(
256
275
  dom,
257
- issueDiv,
276
+ null, // was: container
258
277
  {},
259
278
  issue,
260
279
  CORE_ISSUE_FORM,
261
280
  stateStore,
262
281
  complainIfBad
263
282
  )
264
-
265
- // Descriptions can be long and are stored local to the issue
266
- /*
267
- issueDiv.appendChild(
268
- widgets.makeDescription(
269
- dom,
270
- kb,
271
- issue,
272
- ns.wf('description'),
273
- store,
274
- function (ok, body) {
275
- if (ok) setModifiedDate(store, kb, store)
276
- else console.log('Failed to change description:\n' + body)
277
- }
278
- )
279
- ) */
283
+ issueDiv.appendChild(form)
284
+ form.style.backgroundColor = backgroundColor
280
285
 
281
286
  // Assigned to whom?
282
287
 
283
- const assignments = kb.statementsMatching(issue, ns.wf('assignee'))
288
+ const assignments = store.statementsMatching(issue, ns.wf('assignee'))
284
289
  if (assignments.length > 1) {
285
290
  say('Weird, was assigned to more than one person. Fixing ..')
286
291
  const deletions = assignments.slice(1)
287
- kb.updater.update(deletions, [], function (uri, ok, body) {
292
+ store.updater.update(deletions, [], function (uri, ok, body) {
288
293
  if (ok) {
289
294
  say('Now fixed.')
290
295
  } else {
@@ -297,20 +302,16 @@ export function renderIssue (issue, context) {
297
302
  // Anyone assigned to any issue we know about
298
303
 
299
304
  async function getPossibleAssignees () {
300
- let devs = []
301
- const devGroups = kb.each(issue, ns.wf('assigneeGroup'))
302
- for (let i = 0; i < devGroups.length; i++) {
303
- const group = devGroups[i]
304
- await kb.fetcher.load()
305
- devs = devs.concat(kb.each(group, ns.vcard('member')))
306
- }
305
+ const devGroups = store.each(issue, ns.wf('assigneeGroup'))
306
+ await store.fetcher.load(devGroups) // Load them all
307
+ const groupDevs = devGroups.map(group => store.each(group, ns.vcard('member'), null, group.doc())).flat()
307
308
  // Anyone who is a developer of any project which uses this tracker
308
- const proj = kb.any(null, ns.doap('bug-database'), tracker) // What project?
309
+ const proj = store.any(null, ns.doap('bug-database'), tracker) // What project?
309
310
  if (proj) {
310
- await kb.fetcher.load(proj)
311
- devs = devs.concat(kb.each(proj, ns.doap('developer')))
311
+ await store.fetcher.load(proj)
312
312
  }
313
- return devs
313
+ const projectDevs = proj ? store.each(proj, ns.doap('developer')) : []
314
+ return groupDevs.concat(projectDevs)
314
315
  }
315
316
 
316
317
  // Super issues first - like parent directories .. maybe use breadcrums from?? @@
@@ -322,7 +323,7 @@ export function renderIssue (issue, context) {
322
323
  getPossibleAssignees().then(devs => {
323
324
  if (devs.length) {
324
325
  devs.forEach(function (person) {
325
- kb.fetcher.lookUpThing(person)
326
+ store.fetcher.lookUpThing(person)
326
327
  }) // best effort async for names etc
327
328
  const opts = {
328
329
  // 'mint': '** Add new person **',
@@ -337,14 +338,14 @@ export function renderIssue (issue, context) {
337
338
  issueDiv.appendChild(
338
339
  widgets.makeSelectForOptions(
339
340
  dom,
340
- kb,
341
+ store,
341
342
  issue,
342
343
  ns.wf('assignee'),
343
344
  devs,
344
345
  opts,
345
346
  store,
346
347
  function (ok, body) {
347
- if (ok) setModifiedDate(store, kb, store)
348
+ if (ok) setModifiedDate(store, store, store)
348
349
  else console.log('Failed to change assignee:\n' + body)
349
350
  }
350
351
  )
@@ -352,27 +353,36 @@ export function renderIssue (issue, context) {
352
353
  }
353
354
  })
354
355
 
355
- /* The trees of super issues and subissues
356
+ /* The trees of super-issues and sub-issues
356
357
  */
357
- let subIssuePanel
358
+ function supersOver (issue, stack) {
359
+ stack = stack || []
360
+ const sup = store.any(null, ns.wf('dependent'), issue, issue.doc())
361
+ if (sup) return supersOver(sup, [sup].concat(stack))
362
+ return stack
363
+ }
358
364
  if (getOption(tracker, 'allowSubIssues')) {
359
- if (!subIssuePanel) {
360
- subIssuePanel = issueDiv.appendChild(dom.createElement('div'))
361
- subIssuePanel.style = 'margin: 1em; padding: 1em;'
362
- }
365
+ const subIssuePanel = issueDiv.appendChild(dom.createElement('div'))
366
+ subIssuePanel.style = 'margin: 1em; padding: 1em;'
363
367
 
364
368
  subIssuePanel.appendChild(dom.createElement('h4')).textContent = 'Super Issues'
365
369
  const listOfSupers = subIssuePanel.appendChild(dom.createElement('div'))
370
+ listOfSupers.style.display = 'flex'
366
371
  listOfSupers.refresh = function () {
367
- utils.syncTableToArrayReOrdered(listOfSupers, kb.each(null, ns.wf('dependent'), issue), renderSubIssue)
372
+ // const supers = store.each(null, ns.wf('dependent'), issue, issue.doc())
373
+ const supers = supersOver(issue)
374
+ utils.syncTableToArrayReOrdered(listOfSupers, supers, renderSubIssue)
368
375
  }
369
376
  listOfSupers.refresh()
370
377
 
371
378
  // Sub issues
372
379
  subIssuePanel.appendChild(dom.createElement('h4')).textContent = 'Sub Issues'
373
380
  const listOfSubs = subIssuePanel.appendChild(dom.createElement('div'))
381
+ listOfSubs.style.display = 'flex'
382
+ listOfSubs.style.flexDirection = 'reverse' // Or center
374
383
  listOfSubs.refresh = function () {
375
- utils.syncTableToArrayReOrdered(listOfSubs, kb.each(issue, ns.wf('dependent')), renderSubIssue)
384
+ const subs = store.each(issue, ns.wf('dependent'), null, issue.doc())
385
+ utils.syncTableToArrayReOrdered(listOfSubs, subs, renderSubIssue)
376
386
  }
377
387
  listOfSubs.refresh()
378
388
 
@@ -385,7 +395,7 @@ export function renderIssue (issue, context) {
385
395
  b.addEventListener(
386
396
  'click',
387
397
  function (_event) {
388
- subIssuePanel.insertBefore(newIssueForm(dom, kb, tracker, issue, listOfSubs.refresh), b.nextSibling) // Pop form just after button
398
+ subIssuePanel.insertBefore(newIssueForm(dom, store, tracker, issue, listOfSubs.refresh), b.nextSibling) // Pop form just after button
389
399
  },
390
400
  false
391
401
  )
@@ -394,7 +404,7 @@ export function renderIssue (issue, context) {
394
404
  issueDiv.appendChild(dom.createElement('br'))
395
405
 
396
406
  // Extras are stored centrally to the tracker
397
- const extrasForm = kb.any(tracker, ns.wf('extrasEntryForm'))
407
+ const extrasForm = store.any(tracker, ns.wf('extrasEntryForm'))
398
408
  if (extrasForm) {
399
409
  widgets.appendForm(
400
410
  dom,
@@ -405,40 +415,41 @@ export function renderIssue (issue, context) {
405
415
  stateStore,
406
416
  complainIfBad
407
417
  )
418
+ // issueDiv.appendChild(renderSpacer(backgroundColor))
408
419
  }
409
420
 
410
421
  // Comment/discussion area
411
422
 
412
- const spacer = issueDiv.appendChild(dom.createElement('tr'))
413
- spacer.setAttribute('style', 'height: 1em') // spacer and placeHolder
423
+ const spacer = issueDiv.appendChild(renderSpacer(dom, backgroundColor))
414
424
 
415
- const template = kb.anyValue(tracker, ns.wf('issueURITemplate'))
425
+ const template = store.anyValue(tracker, ns.wf('issueURITemplate'))
416
426
  /*
417
- var chatDocURITemplate = kb.anyValue(tracker, ns.wf('chatDocURITemplate')) // relaive to issue
427
+ var chatDocURITemplate = store.anyValue(tracker, ns.wf('chatDocURITemplate')) // relaive to issue
418
428
  var chat
419
429
  if (chatDocURITemplate) {
420
430
  let template = $rdf.uri.join(chatDocURITemplate, issue.uri) // Template is relative to issue
421
- chat = kb.sym(expandTemplate(template))
431
+ chat = store.sym(expandTemplate(template))
422
432
  } else
423
433
  */
424
434
  let messageStore
425
435
  if (template) {
426
436
  messageStore = issue.doc() // for now. Could go deeper
427
437
  } else {
428
- messageStore = kb.any(tracker, ns.wf('messageStore'))
429
- if (!messageStore) messageStore = kb.any(tracker, ns.wf('stateStore'))
430
- kb.sym(messageStore.uri + '#' + 'Chat' + timestring()) // var chat =
438
+ messageStore = store.any(tracker, ns.wf('messageStore'))
439
+ if (!messageStore) messageStore = store.any(tracker, ns.wf('stateStore'))
440
+ store.sym(messageStore.uri + '#' + 'Chat' + timestring()) // var chat =
431
441
  }
432
442
 
433
- kb.fetcher.nowOrWhenFetched(messageStore, function (ok, body, _xhr) {
443
+ store.fetcher.nowOrWhenFetched(messageStore, function (ok, body, _xhr) {
434
444
  if (!ok) {
435
445
  const er = dom.createElement('p')
436
446
  er.textContent = body // @@ use nice error message
437
447
  issueDiv.insertBefore(er, spacer)
438
448
  } else {
439
- const discussion = messageArea(dom, kb, issue, messageStore)
449
+ const discussion = messageArea(dom, store, issue, messageStore)
440
450
  issueDiv.insertBefore(discussion, spacer)
441
- }
451
+ issueDiv.insertBefore(renderSpacer(dom, backgroundColor), discussion)
452
+ } // Not sure why e stuck this in upwards rather than downwards
442
453
  })
443
454
 
444
455
  // Draggable attachment list
@@ -446,23 +457,22 @@ export function renderIssue (issue, context) {
446
457
  attachmentHint.innerHTML = `<h4>Attachments</h4>
447
458
  <p>Drag files, emails,
448
459
  web pages onto the paper clip, or click the file upload button.</p>`
449
- let uploadFolderURI
450
- if (issue.uri.endsWith('/index.ttl#this')) { // This has a whole folder to itself
451
- uploadFolderURI = issue.uri.slice(0, 14) + 'Files/' // back to slash
452
- } else { // like state.ttl#Iss1587852322438
453
- uploadFolderURI = issue.dir().uri + 'Files/' + issue.uri.split('#')[1] + '/' // New folder for issue in file with others
454
- }
460
+ const uploadFolderURI =
461
+ issue.uri.endsWith('/index.ttl#this') // This has a whole folder to itself
462
+ ? issue.uri.slice(0, 14) + 'Files/' // back to slash
463
+ : issue.dir().uri + 'Files/' + issue.uri.split('#')[1] + '/' // New folder for issue in file with others
464
+
455
465
  widgets.attachmentList(dom, issue, issueDiv, {
456
466
  doc: stateStore,
457
467
  promptIcon: icons.iconBase + 'noun_25830.svg',
458
- uploadFolder: kb.sym(uploadFolderURI), // Allow local files to be uploaded
468
+ uploadFolder: store.sym(uploadFolderURI), // Allow local files to be uploaded
459
469
  predicate: ns.wf('attachment')
460
470
  })
461
471
 
462
472
  // Delete button to delete the issue
463
473
  const deleteButton = widgets.deleteButtonWithCheck(dom, issueDiv, 'issue', async function () {
464
474
  try {
465
- await kb.updater.update(kb.connectedStatements(issue))
475
+ await store.updater.update(store.connectedStatements(issue))
466
476
  } catch (err) {
467
477
  complain(`Unable to delete issue: ${err}`, context)
468
478
  }
@@ -480,7 +490,7 @@ export function renderIssue (issue, context) {
480
490
  'click',
481
491
  async function (_event) {
482
492
  try {
483
- await kb.fetcher.load(messageStore, { force: true, clearPreviousData: true })
493
+ await store.fetcher.load(messageStore, { force: true, clearPreviousData: true })
484
494
  } catch (err) {
485
495
  alert(err)
486
496
  return
package/issuePane.js CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import * as UI from 'solid-ui'
9
+ import { store, authn } from 'solid-logic'
9
10
  import { board } from './board' // @@ will later be in solid-UI
10
11
  import { renderIssue, renderIssueCard, getState, exposeOverlay } from './issue'
11
12
  import { newTrackerButton } from './newTracker'
@@ -15,7 +16,6 @@ import { trackerSettingsFormText } from './trackerSettingsForm.js'
15
16
 
16
17
  const $rdf = UI.rdf
17
18
  const ns = UI.ns
18
- const kb = UI.store
19
19
  const widgets = UI.widgets
20
20
 
21
21
  // const MY_TRACKERS_ICON = UI.icons.iconBase + 'noun_Document_998605.svg'
@@ -36,10 +36,10 @@ export default {
36
36
 
37
37
  // Does the subject deserve an issue pane?
38
38
  label: function (subject, _context) {
39
- const t = kb.findTypeURIs(subject)
39
+ const t = store.findTypeURIs(subject)
40
40
  if (
41
41
  t['http://www.w3.org/2005/01/wf/flow#Task'] ||
42
- kb.holds(subject, UI.ns.wf('tracker'))
42
+ store.holds(subject, UI.ns.wf('tracker'))
43
43
  ) { return 'issue' } // in case ontology not available
44
44
  if (t['http://www.w3.org/2005/01/wf/flow#Tracker']) return 'tracker'
45
45
  // Later: Person. For a list of things assigned to them,
@@ -61,7 +61,7 @@ export default {
61
61
  return Promise.all(updates)
62
62
  }
63
63
 
64
- var kb = context.session.store
64
+ const kb = context.session.store
65
65
  const ns = UI.ns
66
66
  let stateStore
67
67
  if (options.newInstance) {
@@ -73,7 +73,7 @@ export default {
73
73
  const tracker = options.newInstance
74
74
  const appDoc = tracker.doc()
75
75
 
76
- const me = UI.authn.currentUser()
76
+ const me = authn.currentUser()
77
77
  if (me) {
78
78
  kb.add(tracker, ns.dc('author'), me, appDoc)
79
79
  }
@@ -140,73 +140,81 @@ export default {
140
140
  ** This is would not be needed if our quey language
141
141
  ** allowed is to query ardf Collection membership.
142
142
  */
143
- async function fixSubClasses (kb, tracker) {
143
+ async function fixSubClasses (kb, tracker) { // 20220228
144
144
  async function checkOneSuperclass (klass) {
145
145
  const collection = kb.any(klass, ns.owl('disjointUnionOf'), null, doc)
146
146
  if (!collection) throw new Error(`Classification ${klass} has no disjointUnionOf`)
147
147
  if (!collection.elements) throw new Error(`Classification ${klass} has no array`)
148
148
  const needed = new Set(collection.elements.map(x => x.uri))
149
- const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, doc)
150
- .map(x => x.uri))
149
+
150
+ const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, doc).map(x => x.uri))
151
+ const superfluous = existing.filter(sub => !needed.has(sub))
152
+ const deleteActions = superfluous.map(sub => { return { action: 'delete', st: $rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc) } })
153
+ /*
151
154
  for (const sub of existing) {
152
155
  if (!needed.has(sub)) {
153
156
  deletables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc))
154
157
  }
155
158
  }
159
+ */
160
+ const missing = needed.filter(sub => !existing.has(sub))
161
+ const insertActions = missing.ma(sub => { return { action: 'insert', st: $rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc) } })
162
+ /*
156
163
  for (const sub of needed) {
157
164
  if (!existing.has(sub)) {
158
165
  insertables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc))
159
166
  }
160
167
  }
168
+ */
169
+ return deleteActions.concat(insertActions)
161
170
  }
162
171
  const doc = tracker.doc()
163
172
  const states = kb.any(tracker, ns.wf('issueClass'))
164
- const cats = kb.each(tracker, ns.wf('issueCategory'))
165
- var insertables = []
166
- var deletables = []
167
- cats.push(states)
173
+ const cats = kb.each(tracker, ns.wf('issueCategory')).concat([states])
174
+ let damage = [] // to make totally functionaly need to deal with map over async.
168
175
  for (const klass of cats) {
169
- await checkOneSuperclass(klass)
176
+ damage = damage.concat(await checkOneSuperclass(klass))
170
177
  }
171
- const damage = insertables.length + deletables.length
172
- if (damage) {
173
- alert(`Internal error: s${damage} subclasses inconsistences!`)
174
- /*
178
+ if (damage.length) {
179
+ const insertables = damage.filter(fix => fix.action === 'insert').map(fix => fix.st)
180
+ const deletables = damage.filter(fix => fix.action === 'delete').map(fix => fix.st)
181
+ // alert(`Internal error: s${damage} subclasses inconsistences!`)
182
+ console.log('Damage:', damage)
175
183
  if (confirm(`Fix ${damage} inconsistent subclasses in tracker config?`)) {
176
184
  await kb.updater.update(deletables, insertables)
177
- */
185
+ }
178
186
  }
179
187
  }
180
188
 
181
189
  /** /////////////////////////// Board
182
190
  */
183
191
  function renderBoard (tracker, klass) {
184
- const states = kb.any(tracker, ns.wf('issueClass'))
192
+ const states = store.any(tracker, ns.wf('issueClass'))
185
193
  klass = klass || states // default to states
186
194
  const doingStates = klass.sameTerm(states)
187
195
 
188
196
  // These are states we will show by default: the open issues.
189
- const stateArray = kb.any(klass, ns.owl('disjointUnionOf'))
197
+ const stateArray = store.any(klass, ns.owl('disjointUnionOf'))
190
198
  if (!stateArray) {
191
199
  return complain(`Configuration error: state ${states} does not have substates`)
192
200
  }
193
201
  let columnValues = stateArray.elements
194
202
  if (doingStates && columnValues.length > 2 // and there are more than two
195
203
  ) { // strip out closed states
196
- columnValues = columnValues.filter(state => kb.holds(state, ns.rdfs('subClassOf'), ns.wf('Open')) || state.sameTerm(ns.wf('Open')))
204
+ columnValues = columnValues.filter(state => store.holds(state, ns.rdfs('subClassOf'), ns.wf('Open')) || state.sameTerm(ns.wf('Open')))
197
205
  }
198
206
 
199
207
  async function columnDropHandler (issue, newState) {
200
208
  const currentState = getState(issue, klass)
201
- const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
202
- const stateStore = kb.any(tracker, ns.wf('stateStore'))
209
+ const tracker = store.the(issue, ns.wf('tracker'), null, issue.doc())
210
+ const stateStore = store.any(tracker, ns.wf('stateStore'))
203
211
 
204
212
  if (newState.sameTerm(currentState)) {
205
213
  // alert('Same state ' + UI.utils.label(currentState)) // @@ remove
206
214
  return
207
215
  }
208
216
  try {
209
- await kb.updater.update(
217
+ await store.updater.update(
210
218
  [$rdf.st(issue, ns.rdf('type'), currentState, stateStore)],
211
219
  [$rdf.st(issue, ns.rdf('type'), newState, stateStore)])
212
220
  } catch (err) {
@@ -216,7 +224,7 @@ export default {
216
224
  }
217
225
 
218
226
  function isOpen (issue) {
219
- const types = kb.findTypeURIs(issue)
227
+ const types = store.findTypeURIs(issue)
220
228
  return !!types[ns.wf('Open').uri]
221
229
  }
222
230
 
@@ -237,7 +245,7 @@ export default {
237
245
  const refreshButton = widgets.button(dom, UI.icons.iconBase + 'noun_479395.svg',
238
246
  'refresh table', async _event => {
239
247
  try {
240
- await kb.fetcher.load(stateStore, { force: true, clearPreviousData: true })
248
+ await store.fetcher.load(stateStore, { force: true, clearPreviousData: true })
241
249
  } catch (err) {
242
250
  alert(err)
243
251
  return
@@ -253,10 +261,10 @@ export default {
253
261
  query.pat.optional.push(clause)
254
262
  return clause
255
263
  }
256
- const states = kb.any(subject, ns.wf('issueClass'))
257
- const cats = kb.each(tracker, ns.wf('issueCategory')) // zero or more
264
+ const states = store.any(subject, ns.wf('issueClass'))
265
+ const cats = store.each(tracker, ns.wf('issueCategory')) // zero or more
258
266
  const vars = ['issue', 'state', 'created']
259
- var query = new $rdf.Query(UI.utils.label(subject))
267
+ const query = new $rdf.Query(UI.utils.label(subject))
260
268
  for (let i = 0; i < cats.length; i++) {
261
269
  vars.push('_cat_' + i)
262
270
  }
@@ -278,7 +286,7 @@ export default {
278
286
  clause.add(v['_cat_' + i], ns.rdfs('subClassOf'), cats[i])
279
287
  }
280
288
 
281
- const propertyList = kb.any(tracker, ns.wf('propertyList')) // List of extra properties
289
+ const propertyList = store.any(tracker, ns.wf('propertyList')) // List of extra properties
282
290
  if (propertyList) {
283
291
  const properties = propertyList.elements
284
292
  for (let p = 0; p < properties.length; p++) {
@@ -294,10 +302,10 @@ export default {
294
302
  }
295
303
 
296
304
  const selectedStates = {}
297
- const possible = kb.each(undefined, ns.rdfs('subClassOf'), states)
305
+ const possible = store.each(undefined, ns.rdfs('subClassOf'), states)
298
306
  possible.forEach(function (s) {
299
307
  if (
300
- kb.holds(s, ns.rdfs('subClassOf'), ns.wf('Open')) ||
308
+ store.holds(s, ns.rdfs('subClassOf'), ns.wf('Open')) ||
301
309
  s.sameTerm(ns.wf('Open'))
302
310
  ) {
303
311
  selectedStates[s.uri] = true
@@ -321,7 +329,7 @@ export default {
321
329
  '?state': { initialSelection: selectedStates, label: 'Status' }
322
330
  }
323
331
  })
324
- const stateStore = kb.any(subject, ns.wf('stateStore'))
332
+ const stateStore = store.any(subject, ns.wf('stateStore'))
325
333
  tableDiv.appendChild(tableRefreshButton(stateStore, tableDiv))
326
334
  return tableDiv
327
335
  }
@@ -329,7 +337,7 @@ export default {
329
337
  // Allow user to create new things within the folder
330
338
  function renderCreationControl (refreshTarget) {
331
339
  const creationDiv = dom.createElement('div')
332
- const me = UI.authn.currentUser()
340
+ const me = authn.currentUser()
333
341
  const creationContext = {
334
342
  // folder: subject,
335
343
  div: creationDiv,
@@ -348,7 +356,7 @@ export default {
348
356
  function renderInstances (theClass) {
349
357
  const instancesDiv = dom.createElement('div')
350
358
  const context = { dom, div: instancesDiv, noun: 'tracker' }
351
- UI.authn.registrationList(context, { public: true, private: true, type: theClass }).then(_context2 => {
359
+ UI.login.registrationList(context, { public: true, private: true, type: theClass }).then(_context2 => {
352
360
  instancesDiv.appendChild(renderCreationControl(instancesDiv))
353
361
  /* // keep this code in case we need a form
354
362
  const InstancesForm = ns.wf('TrackerInstancesForm')
@@ -364,10 +372,10 @@ export default {
364
372
  const settingsDiv = dom.createElement('div')
365
373
  // A registration control allows the to record this tracker in their type index
366
374
  const context = { dom, div: settingsDiv, noun: 'tracker' }
367
- UI.authn.registrationControl(context, tracker, ns.wf('Tracker')).then(_context2 => {
375
+ UI.login.registrationControl(context, tracker, ns.wf('Tracker')).then(_context2 => {
368
376
  const settingsForm = ns.wf('TrackerSettingsForm')
369
377
  const text = trackerSettingsFormText
370
- $rdf.parse(text, kb, settingsForm.doc().uri, 'text/turtle')
378
+ $rdf.parse(text, store, settingsForm.doc().uri, 'text/turtle')
371
379
  widgets.appendForm(dom, settingsDiv, {}, tracker, settingsForm,
372
380
  tracker.doc(), complainIfBad)
373
381
  })
@@ -385,25 +393,25 @@ export default {
385
393
  ele.appendChild(renderSettings(tracker))
386
394
  } else if (object.sameTerm(instancesView)) {
387
395
  ele.appendChild(renderInstances(ns.wf('Tracker')))
388
- } else if ((kb.holds(tracker, ns.wf('issueCategory'), object)) ||
389
- (kb.holds(tracker, ns.wf('issueClass'), object))) {
396
+ } else if ((store.holds(tracker, ns.wf('issueCategory'), object)) ||
397
+ (store.holds(tracker, ns.wf('issueClass'), object))) {
390
398
  ele.appendChild(renderBoard(tracker, object))
391
399
  } else {
392
400
  throw new Error('Unexpected tab type: ' + object)
393
401
  }
394
402
  }
395
- const states = kb.any(tracker, ns.wf('issueClass'))
403
+ const states = store.any(tracker, ns.wf('issueClass'))
396
404
  const items = [instancesView, tableView, states]
397
- .concat(kb.each(tracker, ns.wf('issueCategory')))
405
+ .concat(store.each(tracker, ns.wf('issueCategory')))
398
406
  items.push(settingsView)
399
- const selectedTab = tableView
407
+ const selectedTab = tableView.uri
400
408
  const options = { renderMain, items, selectedTab }
401
409
 
402
410
  // Add stuff to the ontologies which we believe but they don't say
403
411
  const doc = instancesView.doc()
404
- kb.add(instancesView, ns.rdfs('label'), 'My Trackers', doc) // @@ squatting on wf ns
405
- kb.add(settingsView, ns.rdfs('label'), 'Settings', doc) // @@ squatting on wf ns
406
- kb.add(states, ns.rdfs('label'), 'By State', doc) // @@ squatting on wf ns
412
+ store.add(instancesView, ns.rdfs('label'), 'My Trackers', doc) // @@ squatting on wf ns
413
+ store.add(settingsView, ns.rdfs('label'), 'Settings', doc) // @@ squatting on wf ns
414
+ store.add(states, ns.rdfs('label'), 'By State', doc) // @@ squatting on wf ns
407
415
 
408
416
  const tabs = UI.tabs.tabWidget(options)
409
417
  return tabs
@@ -418,17 +426,17 @@ export default {
418
426
  tracker = subject
419
427
 
420
428
  try {
421
- await fixSubClasses(kb, tracker)
429
+ await fixSubClasses(store, tracker)
422
430
  } catch (err) {
423
431
  console.log('@@@ Error fixing subclasses in config: ' + err)
424
432
  }
425
433
 
426
- const states = kb.any(subject, ns.wf('issueClass'))
434
+ const states = store.any(subject, ns.wf('issueClass'))
427
435
  if (!states) throw new Error('This tracker has no issueClass')
428
- const stateStore = kb.any(subject, ns.wf('stateStore'))
436
+ const stateStore = store.any(subject, ns.wf('stateStore'))
429
437
  if (!stateStore) throw new Error('This tracker has no stateStore')
430
438
 
431
- UI.authn.checkUser() // kick off async operation
439
+ authn.checkUser() // kick off async operation
432
440
 
433
441
  const h = dom.createElement('h2')
434
442
  h.setAttribute('style', 'font-size: 150%')
@@ -437,10 +445,10 @@ export default {
437
445
  h.appendChild(dom.createTextNode(classLabel + ' list')) // Use class label @@I18n
438
446
 
439
447
  // New Issue button
440
- var b = dom.createElement('button')
448
+ const b = dom.createElement('button')
441
449
  const container = dom.createElement('div')
442
450
  b.setAttribute('type', 'button')
443
- b.setAttribute('style', 'padding: 0.3em; font-size: 100%; margin: 0.5em;')
451
+ b.setAttribute('style', 'padding: 0.3em; font-size: 100%; margin: 0.5em; display: flex; align-items: center;')
444
452
  container.appendChild(b)
445
453
  paneDiv.appendChild(container)
446
454
  const img = dom.createElement('img')
@@ -454,7 +462,7 @@ export default {
454
462
  'click',
455
463
  function (_event) {
456
464
  b.disabled = true
457
- container.appendChild(newIssueForm(dom, kb, tracker, null, showNewIssue))
465
+ container.appendChild(newIssueForm(dom, store, tracker, null, showNewIssue))
458
466
  },
459
467
  false
460
468
  )
@@ -490,28 +498,28 @@ export default {
490
498
  const settingsView = ns.wf('SettingsView')
491
499
  const instancesView = ns.wf('InstancesView')
492
500
 
493
- const updater = kb.updater
494
- const t = kb.findTypeURIs(subject)
501
+ const updater = store.updater
502
+ const t = store.findTypeURIs(subject)
495
503
  let tracker
496
504
 
497
505
  // Whatever we are rendering, lets load the ontology
498
506
  const flowOntology = UI.ns.wf('').doc()
499
- if (!kb.holds(undefined, undefined, undefined, flowOntology)) {
507
+ if (!store.holds(undefined, undefined, undefined, flowOntology)) {
500
508
  // If not loaded already
501
- $rdf.parse(require('./wf.js'), kb, flowOntology.uri, 'text/turtle') // Load ontology directly
509
+ $rdf.parse(require('./wf.js'), store, flowOntology.uri, 'text/turtle') // Load ontology directly
502
510
  }
503
511
  const userInterfaceOntology = UI.ns.ui('').doc()
504
- if (!kb.holds(undefined, undefined, undefined, userInterfaceOntology)) {
512
+ if (!store.holds(undefined, undefined, undefined, userInterfaceOntology)) {
505
513
  // If not loaded already
506
- $rdf.parse(require('./ui.js'), kb, userInterfaceOntology.uri, 'text/turtle') // Load ontology directly
514
+ $rdf.parse(require('./ui.js'), store, userInterfaceOntology.uri, 'text/turtle') // Load ontology directly
507
515
  }
508
516
 
509
517
  // Render a single issue
510
518
  if (
511
519
  t['http://www.w3.org/2005/01/wf/flow#Task'] ||
512
- kb.holds(subject, UI.ns.wf('tracker'))
520
+ store.holds(subject, UI.ns.wf('tracker'))
513
521
  ) {
514
- tracker = kb.any(subject, ns.wf('tracker'))
522
+ tracker = store.any(subject, ns.wf('tracker'))
515
523
  if (!tracker) throw new Error('This issue ' + subject + 'has no tracker')
516
524
 
517
525
  // Much data is in the tracker instance, so wait for the data from it
@@ -519,7 +527,7 @@ export default {
519
527
  context.session.store.fetcher
520
528
  .load(tracker.doc())
521
529
  .then(function (_xhrs) {
522
- const stateStore = kb.any(tracker, ns.wf('stateStore'))
530
+ const stateStore = store.any(tracker, ns.wf('stateStore'))
523
531
  context.session.store.fetcher.nowOrWhenFetched(
524
532
  stateStore,
525
533
  subject,
@@ -572,9 +580,7 @@ export default {
572
580
  overlay.style = OVERFLOW_STYLE
573
581
  overlay.style.visibility = 'hidden'
574
582
 
575
- // var overlayPane = null // overlay.appendChild(dom.createElement('div')) // avoid stomping on style by pane
576
-
577
- UI.authn.checkUser().then(webId => {
583
+ authn.checkUser().then(webId => {
578
584
  if (webId) {
579
585
  console.log('Web ID set already: ' + webId)
580
586
  context.me = webId
@@ -582,9 +588,9 @@ export default {
582
588
  return
583
589
  }
584
590
 
585
- loginOutButton = UI.authn.loginStatusBox(dom, webIdUri => {
591
+ loginOutButton = UI.login.loginStatusBox(dom, webIdUri => {
586
592
  if (webIdUri) {
587
- context.me = kb.sym(webIdUri)
593
+ context.me = store.sym(webIdUri)
588
594
  console.log('Web ID set from login button: ' + webIdUri)
589
595
  paneDiv.removeChild(loginOutButton)
590
596
  // enable things
package/newIssue.js CHANGED
@@ -19,7 +19,6 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
19
19
  titlefield.setAttribute('class', 'pendingedit')
20
20
  titlefield.disabled = true
21
21
  const sts = []
22
- let issue
23
22
 
24
23
  const expandTemplate = function (template) {
25
24
  const now = new $rdf.Literal(new Date())
@@ -34,34 +33,30 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
34
33
  .replace('{DD}', DD)
35
34
  }
36
35
  // Where to store the new issue?
37
- let template = kb.anyValue(tracker, ns.wf('issueURITemplate'))
38
- let issueDoc
39
- if (template) {
36
+ const template = kb.anyValue(tracker, ns.wf('issueURITemplate'))
37
+ const issue = template
40
38
  // Does each issue do in its own file?
41
- template = $rdf.uri.join(template, stateStore.uri) // Template is relative
42
- issue = kb.sym(expandTemplate(template))
43
- } else {
44
- issue = kb.sym(stateStore.uri + '#' + 'Iss' + timestring())
45
- }
46
- // eslint-disable-next-line prefer-const
47
- issueDoc = issue.doc()
39
+ ? kb.sym(expandTemplate($rdf.uri.join(template, stateStore.uri)))
40
+ : kb.sym(stateStore.uri + '#' + 'Iss' + timestring())
41
+
42
+ const issueDoc = issue.doc()
48
43
 
49
44
  // Basic 9 core predicates are stored in the main stateStore
50
45
 
51
46
  const title = kb.literal(titlefield.value)
52
47
  sts.push(new $rdf.Statement(issue, ns.wf('tracker'), tracker, stateStore))
53
48
  sts.push(new $rdf.Statement(issue, ns.dc('title'), title, stateStore))
54
- sts.push(
55
- new $rdf.Statement(issue, ns.dct('created'), new Date(), stateStore)
56
- )
57
- const initialStates = kb.each(tracker, ns.wf('initialState'))
58
- if (initialStates.length === 0) { console.log('This tracker has no initialState') }
59
- for (let i = 0; i < initialStates.length; i++) {
49
+ sts.push(new $rdf.Statement(issue, ns.dct('created'), new Date(), stateStore))
50
+ // Copy states from super issue as after all they are subtasks so initially same state same category
51
+ const initialStates = superIssue
52
+ ? kb.each(superIssue, ns.rdf('type'), null, superIssue.doc())
53
+ : kb.each(tracker, ns.wf('initialState'))
54
+ for (const state of initialStates) {
60
55
  sts.push(
61
56
  new $rdf.Statement(
62
57
  issue,
63
58
  ns.rdf('type'),
64
- initialStates[i],
59
+ state,
65
60
  stateStore
66
61
  )
67
62
  )
@@ -100,7 +95,7 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
100
95
  '</h2><p>Title of new ' +
101
96
  classLabel +
102
97
  ':</p>'
103
- var titlefield = dom.createElement('input')
98
+ const titlefield = dom.createElement('input')
104
99
  titlefield.setAttribute('type', 'text')
105
100
  titlefield.setAttribute(
106
101
  'style',
@@ -119,5 +114,6 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
119
114
  false
120
115
  )
121
116
  form.appendChild(titlefield)
117
+ titlefield.focus() // we want user cursor here
122
118
  return form
123
119
  }
package/newTracker.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as UI from 'solid-ui'
2
+ import { store } from 'solid-logic'
2
3
 
3
4
  const $rdf = UI.rdf
4
5
  const ns = UI.ns
5
- const kb = UI.store
6
- const updater = kb.updater
6
+ const updater = store.updater
7
7
 
8
8
  /* Button for making a whole new tracker
9
9
  ** This is the least tesetd part of the tracker system at the moment.
@@ -16,17 +16,30 @@ export function newTrackerButton (thisTracker, context) {
16
16
  }
17
17
 
18
18
  // const dom = context.dom
19
- const button = UI.authn.newAppInstance(context.dom, { noun: 'tracker' }, function (
19
+ const button = UI.login.newAppInstance(context.dom, { noun: 'tracker' }, function (
20
20
  ws,
21
21
  base
22
22
  ) {
23
+ function morph (x) {
24
+ // Move any URIs in this space into that space
25
+ if (x.elements !== undefined) return x.elements.map(morph) // Morph within lists
26
+ if (x.uri === undefined) return x
27
+ let u = x.uri
28
+ if (u === stateStore.uri) return newStore // special case
29
+ if (u.slice(0, oldBase.length) === oldBase) {
30
+ u = base + u.slice(oldBase.length)
31
+ $rdf.log.debug(' Map ' + x.uri + ' to ' + u)
32
+ }
33
+ return store.sym(u)
34
+ }
35
+
23
36
  const appPathSegment = 'issuetracker.w3.org' // how to allocate this string and connect to
24
37
  // console.log("Ready to make new instance at "+ws)
25
38
  const sp = UI.ns.space
26
- const kb = context.session.store
39
+ const store = context.session.store
27
40
 
28
41
  if (!base) {
29
- base = kb.any(ws, sp('uriPrefix')).value
42
+ base = store.any(ws, sp('uriPrefix')).value
30
43
  if (base.slice(-1) !== '/') {
31
44
  $rdf.log.error(
32
45
  appPathSegment + ': No / at end of uriPrefix ' + base
@@ -39,29 +52,17 @@ export function newTrackerButton (thisTracker, context) {
39
52
  }
40
53
  }
41
54
 
42
- const stateStore = kb.any(thisTracker, ns.wf('stateStore'))
43
- const newStore = kb.sym(base + 'store.ttl')
55
+ const stateStore = store.any(thisTracker, ns.wf('stateStore'))
56
+ const newStore = store.sym(base + 'store.ttl')
44
57
 
45
58
  const here = thisTracker.doc()
46
59
 
47
60
  const oldBase = here.uri.slice(0, here.uri.lastIndexOf('/') + 1)
48
61
 
49
- var morph = function (x) {
50
- // Move any URIs in this space into that space
51
- if (x.elements !== undefined) return x.elements.map(morph) // Morph within lists
52
- if (x.uri === undefined) return x
53
- let u = x.uri
54
- if (u === stateStore.uri) return newStore // special case
55
- if (u.slice(0, oldBase.length) === oldBase) {
56
- u = base + u.slice(oldBase.length)
57
- $rdf.log.debug(' Map ' + x.uri + ' to ' + u)
58
- }
59
- return kb.sym(u)
60
- }
61
62
  const there = morph(here)
62
63
  const newTracker = morph(thisTracker)
63
64
 
64
- const myConfig = kb.statementsMatching(
65
+ const myConfig = store.statementsMatching(
65
66
  undefined,
66
67
  undefined,
67
68
  undefined,
@@ -69,7 +70,7 @@ export function newTrackerButton (thisTracker, context) {
69
70
  )
70
71
  for (let i = 0; i < myConfig.length; i++) {
71
72
  const st = myConfig[i]
72
- kb.add(
73
+ store.add(
73
74
  morph(st.subject),
74
75
  morph(st.predicate),
75
76
  morph(st.object),
@@ -79,15 +80,15 @@ export function newTrackerButton (thisTracker, context) {
79
80
 
80
81
  // Keep a paper trail @@ Revisit when we have non-public ones @@ Privacy
81
82
  //
82
- kb.add(newTracker, UI.ns.space('inspiration'), thisTracker, stateStore)
83
+ store.add(newTracker, UI.ns.space('inspiration'), thisTracker, stateStore)
83
84
 
84
- kb.add(newTracker, UI.ns.space('inspiration'), thisTracker, there)
85
+ store.add(newTracker, UI.ns.space('inspiration'), thisTracker, there)
85
86
 
86
- // $rdf.log.debug("\n Ready to put " + kb.statementsMatching(undefined, undefined, undefined, there)); //@@
87
+ // $rdf.log.debug("\n Ready to put " + store.statementsMatching(undefined, undefined, undefined, there)); //@@
87
88
 
88
89
  updater.put(
89
90
  there,
90
- kb.statementsMatching(undefined, undefined, undefined, there),
91
+ store.statementsMatching(undefined, undefined, undefined, there),
91
92
  'text/turtle',
92
93
  function (uri2, ok, message) {
93
94
  if (ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issue-pane",
3
- "version": "2.4.9",
3
+ "version": "2.4.10-0fa14c64",
4
4
  "description": "Solid-compatible Panes: issue editor",
5
5
  "main": "./issuePane.js",
6
6
  "scripts": {
@@ -8,8 +8,8 @@
8
8
  "lint": "eslint '*.js'",
9
9
  "lint-fix": "eslint '*.js' --fix",
10
10
  "test": "npm run lint",
11
- "prepublishOnly": "npm test",
12
- "postpublish": "git push origin main --follow-tags"
11
+ "ignore:prepublishOnly": "npm test",
12
+ "ignore:postpublish": "git push origin main --follow-tags"
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
@@ -34,15 +34,16 @@
34
34
  },
35
35
  "homepage": "https://github.com/solid/issue-pane",
36
36
  "dependencies": {
37
- "pane-registry": "^2.4.6",
38
- "rdflib": "^2.2.17",
39
- "solid-ui": "^2.4.15"
37
+ "pane-registry": "^2.4.7",
38
+ "rdflib": "^2.2.18",
39
+ "solid-logic": "^1.3.14",
40
+ "solid-ui": "^2.4.19"
40
41
  },
41
42
  "devDependencies": {
42
- "eslint": "^7.32.0",
43
+ "eslint": "^8.11.0",
44
+ "eslint-plugin-import": "^2.25.4",
43
45
  "husky": "^7.0.4",
44
- "lint-staged": "^11.2.6",
45
- "standard": "^16.0.4"
46
+ "lint-staged": "^12.3.7"
46
47
  },
47
48
  "husky": {
48
49
  "hooks": {
package/tbl-bug-22.png CHANGED
File without changes
File without changes
File without changes
package/ui.js CHANGED
File without changes
package/ui.ttl CHANGED
File without changes
package/wf.js CHANGED
File without changes
package/wf.ttl CHANGED
File without changes