issue-pane 2.4.9-5fd734ff → 2.4.9-e1b104be

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/board.js CHANGED
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import * as UI from 'solid-ui'
14
- import { store } from 'solid-logic'
14
+ const kb = UI.store
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 = store.sym(u)
41
+ const item = kb.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 = store.each(item, ns.rdf('type'))
58
- const catColors = classes.map(cat => store.any(cat, ns.ui('backgroundColor'))).filter(c => c)
57
+ const classes = kb.each(item, ns.rdf('type'))
58
+ const catColors = classes.map(cat => kb.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] || store.any(category, ns.ui('backgroundColor'))
63
+ const backgroundColor = catColors[0] || kb.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 => [store.any(x, predicate) || defaultSortValue, x])
69
+ const toBeSorted = values.map(x => [kb.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 = store.each(null, ns.rdf('type'), category)
85
+ let items = kb.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,24 +1,36 @@
1
1
  // All the UI for a single issue, without store load or listening for changes
2
2
  //
3
- import { icons, messageArea, ns, rdf, style, utils, widgets } from 'solid-ui'
4
- import { authn, store } from 'solid-logic'
3
+ import { authn, icons, messageArea, ns, rdf, store, style, utils, widgets } from 'solid-ui'
5
4
  import { newIssueForm } from './newIssue'
6
5
 
7
6
  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 = kb.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 = store.the(issue, ns.wf('tracker'), null, issue.doc())
18
- const states = store.any(tracker, ns.wf('issueClass'))
29
+ const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
30
+ const states = kb.any(tracker, ns.wf('issueClass'))
19
31
  classification = classification || states
20
- const types = store.each(issue, ns.rdf('type'))
21
- .filter(ty => store.holds(ty, ns.rdfs('subClassOf'), classification))
32
+ const types = kb.each(issue, ns.rdf('type'))
33
+ .filter(ty => kb.holds(ty, ns.rdfs('subClassOf'), classification))
22
34
  if (types.length !== 1) {
23
35
  // const initialState = kb.any(tracker, ns.wf('initialState')) No do NOT default
24
36
  // if (initialState) return initialState
@@ -29,8 +41,8 @@ export function getState (issue, classification) {
29
41
 
30
42
  export function renderIssueCard (issue, context) {
31
43
  function getBackgroundColor () {
32
- const classes = store.each(issue, ns.rdf('type')) // @@ pick cats in order then state
33
- const catColors = classes.map(cat => store.any(cat, ns.ui('backgroundColor'))).filter(c => !!c)
44
+ const classes = kb.each(issue, ns.rdf('type')) // @@ pick cats in order then state
45
+ const catColors = classes.map(cat => kb.any(cat, ns.ui('backgroundColor'))).filter(c => !!c)
34
46
 
35
47
  if (catColors.length) return catColors[0].value // pick first one
36
48
  return null
@@ -46,7 +58,7 @@ export function renderIssueCard (issue, context) {
46
58
  const card = dom.createElement('div')
47
59
  const table = card.appendChild(dom.createElement('table'))
48
60
  table.style.width = '100%'
49
- const options = { draggable: false } // Let the baord make th ewhole card draggable
61
+ const options = { draggable: false } // Let the baord make the whole card draggable
50
62
  table.appendChild(widgets.personTR(dom, null, issue, options))
51
63
  table.subject = issue
52
64
  card.style = 'border-radius: 0.4em; border: 0.05em solid grey; margin: 0.3em;'
@@ -66,7 +78,7 @@ export function renderIssueCard (issue, context) {
66
78
  if (uncategorized) {
67
79
  const deleteButton = widgets.deleteButtonWithCheck(dom, buttonsCell, 'issue', async function () { // noun?
68
80
  try {
69
- await store.updater.update(store.connectedStatements(issue))
81
+ await kb.updater.update(kb.connectedStatements(issue))
70
82
  } catch (err) {
71
83
  complain(`Unable to delete issue: ${err}`, context)
72
84
  }
@@ -102,16 +114,15 @@ export function exposeOverlay (subject, context) {
102
114
 
103
115
  export function renderIssue (issue, context) {
104
116
  // Don't bother changing the last modified dates of things: save time
105
- function setModifiedDate (subj, store, doc) {
117
+ function setModifiedDate (subj, kb, doc) {
106
118
  if (SET_MODIFIED_DATES) {
107
119
  if (!getOption(tracker, 'trackLastModified')) return
108
- let deletions = store.statementsMatching(issue, ns.dct('modified'))
109
- deletions = deletions.concat(
110
- store.statementsMatching(issue, ns.wf('modifiedBy'))
111
- )
120
+ const deletions = kb.statementsMatching(issue, ns.dct('modified'))
121
+ .concat(kb.statementsMatching(issue, ns.wf('modifiedBy'))
122
+ )
112
123
  const insertions = [$rdf.st(issue, ns.dct('modified'), new Date(), doc)]
113
124
  if (me) insertions.push($rdf.st(issue, ns.wf('modifiedBy'), me, doc))
114
- store.updater.update(deletions, insertions, function (_uri, _ok, _body) {})
125
+ kb.updater.update(deletions, insertions, function (_uri, _ok, _body) {})
115
126
  }
116
127
  }
117
128
 
@@ -144,32 +155,32 @@ export function renderIssue (issue, context) {
144
155
  }
145
156
  function getOption (tracker, option) {
146
157
  // eg 'allowSubIssues'
147
- const opt = store.any(tracker, ns.ui(option))
158
+ const opt = kb.any(tracker, ns.ui(option))
148
159
  return !!(opt && opt.value)
149
160
  }
150
161
 
151
162
  function setPaneStyle () {
152
- const types = store.findTypeURIs(issue)
153
- let mystyle = 'padding: 0.5em 1.5em 1em 1.5em; '
163
+ const types = kb.findTypeURIs(issue)
164
+ const mystyle0 = 'padding: 0.5em 1.5em 1em 1.5em; '
154
165
  let backgroundColor = null
155
166
  for (const uri in types) {
156
- backgroundColor = store.any(
157
- store.sym(uri),
158
- store.sym('http://www.w3.org/ns/ui#backgroundColor')
167
+ backgroundColor = kb.any(
168
+ kb.sym(uri),
169
+ kb.sym('http://www.w3.org/ns/ui#backgroundColor')
159
170
  )
160
171
  if (backgroundColor) break
161
172
  }
162
173
  backgroundColor = backgroundColor ? backgroundColor.value : '#eee' // default grey
163
- mystyle += 'background-color: ' + backgroundColor + '; '
174
+ const mystyle = mystyle0 + 'background-color: ' + backgroundColor + '; '
164
175
  issueDiv.setAttribute('style', mystyle)
165
176
  }
166
177
 
178
+ /// ////////////// Body of renderIssue
179
+
167
180
  const dom = context.dom
168
- // eslint-disable-next-line no-use-before-define
169
- const tracker = store.the(issue, ns.wf('tracker'), null, issue.doc())
181
+ const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
170
182
  if (!tracker) throw new Error('No tracker')
171
- // eslint-disable-next-line no-use-before-define
172
- const stateStore = store.any(tracker, ns.wf('stateStore'))
183
+ const stateStore = kb.any(tracker, ns.wf('stateStore'))
173
184
  const store = issue.doc()
174
185
 
175
186
  const issueDiv = dom.createElement('div')
@@ -179,17 +190,20 @@ export function renderIssue (issue, context) {
179
190
 
180
191
  authn.checkUser() // kick off async operation
181
192
 
182
- const states = store.any(tracker, ns.wf('issueClass'))
193
+ const iconButton = issueDiv.appendChild(widgets.button(dom, iconForIssue(issue)))
194
+ widgets.makeDraggable(iconButton, issue) // Drag me wherever you need to do stuff with this issue
195
+
196
+ const states = kb.any(tracker, ns.wf('issueClass'))
183
197
  if (!states) { throw new Error('This tracker ' + tracker + ' has no issueClass') }
184
198
  const select = widgets.makeSelectForCategory(
185
199
  dom,
186
- store,
200
+ kb,
187
201
  issue,
188
202
  states,
189
203
  stateStore,
190
204
  function (ok, body) {
191
205
  if (ok) {
192
- setModifiedDate(store, store, store)
206
+ setModifiedDate(store, kb, store)
193
207
  widgets.refreshTree(issueDiv)
194
208
  } else {
195
209
  console.log('Failed to change state:\n' + body)
@@ -198,18 +212,18 @@ export function renderIssue (issue, context) {
198
212
  )
199
213
  issueDiv.appendChild(select)
200
214
 
201
- const cats = store.each(tracker, ns.wf('issueCategory')) // zero or more
202
- for (let i = 0; i < cats.length; i++) {
215
+ const cats = kb.each(tracker, ns.wf('issueCategory')) // zero or more
216
+ for (const cat of cats) {
203
217
  issueDiv.appendChild(
204
218
  widgets.makeSelectForCategory(
205
219
  dom,
206
- store,
220
+ kb,
207
221
  issue,
208
- cats[i],
222
+ cat,
209
223
  stateStore,
210
224
  function (ok, body) {
211
225
  if (ok) {
212
- setModifiedDate(store, store, store)
226
+ setModifiedDate(store, kb, store)
213
227
  widgets.refreshTree(issueDiv)
214
228
  } else {
215
229
  console.log('Failed to change category:\n' + body)
@@ -253,7 +267,7 @@ export function renderIssue (issue, context) {
253
267
  wf:Task :creationForm core:coreIsueForm .
254
268
  `
255
269
  const CORE_ISSUE_FORM = ns.wf('coreIsueForm')
256
- $rdf.parse(coreIssueFormText, store, CORE_ISSUE_FORM.doc().uri, 'text/turtle')
270
+ $rdf.parse(coreIssueFormText, kb, CORE_ISSUE_FORM.doc().uri, 'text/turtle')
257
271
  widgets.appendForm(
258
272
  dom,
259
273
  issueDiv,
@@ -282,11 +296,11 @@ export function renderIssue (issue, context) {
282
296
 
283
297
  // Assigned to whom?
284
298
 
285
- const assignments = store.statementsMatching(issue, ns.wf('assignee'))
299
+ const assignments = kb.statementsMatching(issue, ns.wf('assignee'))
286
300
  if (assignments.length > 1) {
287
301
  say('Weird, was assigned to more than one person. Fixing ..')
288
302
  const deletions = assignments.slice(1)
289
- store.updater.update(deletions, [], function (uri, ok, body) {
303
+ kb.updater.update(deletions, [], function (uri, ok, body) {
290
304
  if (ok) {
291
305
  say('Now fixed.')
292
306
  } else {
@@ -299,20 +313,16 @@ export function renderIssue (issue, context) {
299
313
  // Anyone assigned to any issue we know about
300
314
 
301
315
  async function getPossibleAssignees () {
302
- let devs = []
303
- const devGroups = store.each(issue, ns.wf('assigneeGroup'))
304
- for (let i = 0; i < devGroups.length; i++) {
305
- const group = devGroups[i]
306
- await store.fetcher.load()
307
- devs = devs.concat(store.each(group, ns.vcard('member')))
308
- }
316
+ const devGroups = kb.each(issue, ns.wf('assigneeGroup'))
317
+ await kb.fetcher.load(devGroups) // Load them all
318
+ const groupDevs = devGroups.map(group => kb.each(group, ns.vcard('member'), null, group.doc())).flat()
309
319
  // Anyone who is a developer of any project which uses this tracker
310
- const proj = store.any(null, ns.doap('bug-database'), tracker) // What project?
320
+ const proj = kb.any(null, ns.doap('bug-database'), tracker) // What project?
311
321
  if (proj) {
312
- await store.fetcher.load(proj)
313
- devs = devs.concat(store.each(proj, ns.doap('developer')))
322
+ await kb.fetcher.load(proj)
314
323
  }
315
- return devs
324
+ const projectDevs = proj ? kb.each(proj, ns.doap('developer')) : []
325
+ return groupDevs.concat(projectDevs)
316
326
  }
317
327
 
318
328
  // Super issues first - like parent directories .. maybe use breadcrums from?? @@
@@ -324,7 +334,7 @@ export function renderIssue (issue, context) {
324
334
  getPossibleAssignees().then(devs => {
325
335
  if (devs.length) {
326
336
  devs.forEach(function (person) {
327
- store.fetcher.lookUpThing(person)
337
+ kb.fetcher.lookUpThing(person)
328
338
  }) // best effort async for names etc
329
339
  const opts = {
330
340
  // 'mint': '** Add new person **',
@@ -339,14 +349,14 @@ export function renderIssue (issue, context) {
339
349
  issueDiv.appendChild(
340
350
  widgets.makeSelectForOptions(
341
351
  dom,
342
- store,
352
+ kb,
343
353
  issue,
344
354
  ns.wf('assignee'),
345
355
  devs,
346
356
  opts,
347
357
  store,
348
358
  function (ok, body) {
349
- if (ok) setModifiedDate(store, store, store)
359
+ if (ok) setModifiedDate(store, kb, store)
350
360
  else console.log('Failed to change assignee:\n' + body)
351
361
  }
352
362
  )
@@ -366,7 +376,7 @@ export function renderIssue (issue, context) {
366
376
  subIssuePanel.appendChild(dom.createElement('h4')).textContent = 'Super Issues'
367
377
  const listOfSupers = subIssuePanel.appendChild(dom.createElement('div'))
368
378
  listOfSupers.refresh = function () {
369
- utils.syncTableToArrayReOrdered(listOfSupers, store.each(null, ns.wf('dependent'), issue), renderSubIssue)
379
+ utils.syncTableToArrayReOrdered(listOfSupers, kb.each(null, ns.wf('dependent'), issue), renderSubIssue)
370
380
  }
371
381
  listOfSupers.refresh()
372
382
 
@@ -374,7 +384,7 @@ export function renderIssue (issue, context) {
374
384
  subIssuePanel.appendChild(dom.createElement('h4')).textContent = 'Sub Issues'
375
385
  const listOfSubs = subIssuePanel.appendChild(dom.createElement('div'))
376
386
  listOfSubs.refresh = function () {
377
- utils.syncTableToArrayReOrdered(listOfSubs, store.each(issue, ns.wf('dependent')), renderSubIssue)
387
+ utils.syncTableToArrayReOrdered(listOfSubs, kb.each(issue, ns.wf('dependent')), renderSubIssue)
378
388
  }
379
389
  listOfSubs.refresh()
380
390
 
@@ -387,7 +397,7 @@ export function renderIssue (issue, context) {
387
397
  b.addEventListener(
388
398
  'click',
389
399
  function (_event) {
390
- subIssuePanel.insertBefore(newIssueForm(dom, store, tracker, issue, listOfSubs.refresh), b.nextSibling) // Pop form just after button
400
+ subIssuePanel.insertBefore(newIssueForm(dom, kb, tracker, issue, listOfSubs.refresh), b.nextSibling) // Pop form just after button
391
401
  },
392
402
  false
393
403
  )
@@ -396,7 +406,7 @@ export function renderIssue (issue, context) {
396
406
  issueDiv.appendChild(dom.createElement('br'))
397
407
 
398
408
  // Extras are stored centrally to the tracker
399
- const extrasForm = store.any(tracker, ns.wf('extrasEntryForm'))
409
+ const extrasForm = kb.any(tracker, ns.wf('extrasEntryForm'))
400
410
  if (extrasForm) {
401
411
  widgets.appendForm(
402
412
  dom,
@@ -414,7 +424,7 @@ export function renderIssue (issue, context) {
414
424
  const spacer = issueDiv.appendChild(dom.createElement('tr'))
415
425
  spacer.setAttribute('style', 'height: 1em') // spacer and placeHolder
416
426
 
417
- const template = store.anyValue(tracker, ns.wf('issueURITemplate'))
427
+ const template = kb.anyValue(tracker, ns.wf('issueURITemplate'))
418
428
  /*
419
429
  var chatDocURITemplate = kb.anyValue(tracker, ns.wf('chatDocURITemplate')) // relaive to issue
420
430
  var chat
@@ -427,18 +437,18 @@ export function renderIssue (issue, context) {
427
437
  if (template) {
428
438
  messageStore = issue.doc() // for now. Could go deeper
429
439
  } else {
430
- messageStore = store.any(tracker, ns.wf('messageStore'))
431
- if (!messageStore) messageStore = store.any(tracker, ns.wf('stateStore'))
432
- store.sym(messageStore.uri + '#' + 'Chat' + timestring()) // var chat =
440
+ messageStore = kb.any(tracker, ns.wf('messageStore'))
441
+ if (!messageStore) messageStore = kb.any(tracker, ns.wf('stateStore'))
442
+ kb.sym(messageStore.uri + '#' + 'Chat' + timestring()) // var chat =
433
443
  }
434
444
 
435
- store.fetcher.nowOrWhenFetched(messageStore, function (ok, body, _xhr) {
445
+ kb.fetcher.nowOrWhenFetched(messageStore, function (ok, body, _xhr) {
436
446
  if (!ok) {
437
447
  const er = dom.createElement('p')
438
448
  er.textContent = body // @@ use nice error message
439
449
  issueDiv.insertBefore(er, spacer)
440
450
  } else {
441
- const discussion = messageArea(dom, store, issue, messageStore)
451
+ const discussion = messageArea(dom, kb, issue, messageStore)
442
452
  issueDiv.insertBefore(discussion, spacer)
443
453
  }
444
454
  })
@@ -448,23 +458,22 @@ export function renderIssue (issue, context) {
448
458
  attachmentHint.innerHTML = `<h4>Attachments</h4>
449
459
  <p>Drag files, emails,
450
460
  web pages onto the paper clip, or click the file upload button.</p>`
451
- let uploadFolderURI
452
- if (issue.uri.endsWith('/index.ttl#this')) { // This has a whole folder to itself
453
- uploadFolderURI = issue.uri.slice(0, 14) + 'Files/' // back to slash
454
- } else { // like state.ttl#Iss1587852322438
455
- uploadFolderURI = issue.dir().uri + 'Files/' + issue.uri.split('#')[1] + '/' // New folder for issue in file with others
456
- }
461
+ const uploadFolderURI =
462
+ issue.uri.endsWith('/index.ttl#this') // This has a whole folder to itself
463
+ ? issue.uri.slice(0, 14) + 'Files/' // back to slash
464
+ : issue.dir().uri + 'Files/' + issue.uri.split('#')[1] + '/' // New folder for issue in file with others
465
+
457
466
  widgets.attachmentList(dom, issue, issueDiv, {
458
467
  doc: stateStore,
459
468
  promptIcon: icons.iconBase + 'noun_25830.svg',
460
- uploadFolder: store.sym(uploadFolderURI), // Allow local files to be uploaded
469
+ uploadFolder: kb.sym(uploadFolderURI), // Allow local files to be uploaded
461
470
  predicate: ns.wf('attachment')
462
471
  })
463
472
 
464
473
  // Delete button to delete the issue
465
474
  const deleteButton = widgets.deleteButtonWithCheck(dom, issueDiv, 'issue', async function () {
466
475
  try {
467
- await store.updater.update(store.connectedStatements(issue))
476
+ await kb.updater.update(kb.connectedStatements(issue))
468
477
  } catch (err) {
469
478
  complain(`Unable to delete issue: ${err}`, context)
470
479
  }
@@ -482,7 +491,7 @@ export function renderIssue (issue, context) {
482
491
  'click',
483
492
  async function (_event) {
484
493
  try {
485
- await store.fetcher.load(messageStore, { force: true, clearPreviousData: true })
494
+ await kb.fetcher.load(messageStore, { force: true, clearPreviousData: true })
486
495
  } catch (err) {
487
496
  alert(err)
488
497
  return
package/issuePane.js CHANGED
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  import * as UI from 'solid-ui'
9
- import { store, authn } from 'solid-logic'
10
9
  import { board } from './board' // @@ will later be in solid-UI
11
10
  import { renderIssue, renderIssueCard, getState, exposeOverlay } from './issue'
12
11
  import { newTrackerButton } from './newTracker'
@@ -16,6 +15,7 @@ import { trackerSettingsFormText } from './trackerSettingsForm.js'
16
15
 
17
16
  const $rdf = UI.rdf
18
17
  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 = store.findTypeURIs(subject)
39
+ const t = kb.findTypeURIs(subject)
40
40
  if (
41
41
  t['http://www.w3.org/2005/01/wf/flow#Task'] ||
42
- store.holds(subject, UI.ns.wf('tracker'))
42
+ kb.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 = authn.currentUser()
76
+ const me = UI.authn.currentUser()
77
77
  if (me) {
78
78
  kb.add(tracker, ns.dc('author'), me, appDoc)
79
79
  }
@@ -148,65 +148,73 @@ export default {
148
148
  const needed = new Set(collection.elements.map(x => x.uri))
149
149
  const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, doc)
150
150
  .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 = await damage.concat(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 = store.any(tracker, ns.wf('issueClass'))
192
+ const states = kb.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 = store.any(klass, ns.owl('disjointUnionOf'))
197
+ const stateArray = kb.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 => store.holds(state, ns.rdfs('subClassOf'), ns.wf('Open')) || state.sameTerm(ns.wf('Open')))
204
+ columnValues = columnValues.filter(state => kb.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 = store.the(issue, ns.wf('tracker'), null, issue.doc())
202
- const stateStore = store.any(tracker, ns.wf('stateStore'))
209
+ const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
210
+ const stateStore = kb.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 store.updater.update(
217
+ await kb.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 = store.findTypeURIs(issue)
227
+ const types = kb.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 store.fetcher.load(stateStore, { force: true, clearPreviousData: true })
248
+ await kb.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 = store.any(subject, ns.wf('issueClass'))
257
- const cats = store.each(tracker, ns.wf('issueCategory')) // zero or more
264
+ const states = kb.any(subject, ns.wf('issueClass'))
265
+ const cats = kb.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 = store.any(tracker, ns.wf('propertyList')) // List of extra properties
289
+ const propertyList = kb.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 = store.each(undefined, ns.rdfs('subClassOf'), states)
305
+ const possible = kb.each(undefined, ns.rdfs('subClassOf'), states)
298
306
  possible.forEach(function (s) {
299
307
  if (
300
- store.holds(s, ns.rdfs('subClassOf'), ns.wf('Open')) ||
308
+ kb.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 = store.any(subject, ns.wf('stateStore'))
332
+ const stateStore = kb.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 = authn.currentUser()
340
+ const me = UI.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.login.registrationList(context, { public: true, private: true, type: theClass }).then(_context2 => {
359
+ UI.authn.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.login.registrationControl(context, tracker, ns.wf('Tracker')).then(_context2 => {
375
+ UI.authn.registrationControl(context, tracker, ns.wf('Tracker')).then(_context2 => {
368
376
  const settingsForm = ns.wf('TrackerSettingsForm')
369
377
  const text = trackerSettingsFormText
370
- $rdf.parse(text, store, settingsForm.doc().uri, 'text/turtle')
378
+ $rdf.parse(text, kb, 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 ((store.holds(tracker, ns.wf('issueCategory'), object)) ||
389
- (store.holds(tracker, ns.wf('issueClass'), object))) {
396
+ } else if ((kb.holds(tracker, ns.wf('issueCategory'), object)) ||
397
+ (kb.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 = store.any(tracker, ns.wf('issueClass'))
403
+ const states = kb.any(tracker, ns.wf('issueClass'))
396
404
  const items = [instancesView, tableView, states]
397
- .concat(store.each(tracker, ns.wf('issueCategory')))
405
+ .concat(kb.each(tracker, ns.wf('issueCategory')))
398
406
  items.push(settingsView)
399
407
  const selectedTab = tableView
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
- store.add(instancesView, ns.rdfs('label'), 'My Trackers', doc) // @@ squatting on wf ns
405
- store.add(settingsView, ns.rdfs('label'), 'Settings', doc) // @@ squatting on wf ns
406
- store.add(states, ns.rdfs('label'), 'By State', doc) // @@ squatting on wf ns
412
+ kb.add(instancesView, ns.rdfs('label'), 'My Trackers', doc) // @@ squatting on wf ns
413
+ kb.add(settingsView, ns.rdfs('label'), 'Settings', doc) // @@ squatting on wf ns
414
+ kb.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(store, tracker)
429
+ await fixSubClasses(kb, tracker)
422
430
  } catch (err) {
423
431
  console.log('@@@ Error fixing subclasses in config: ' + err)
424
432
  }
425
433
 
426
- const states = store.any(subject, ns.wf('issueClass'))
434
+ const states = kb.any(subject, ns.wf('issueClass'))
427
435
  if (!states) throw new Error('This tracker has no issueClass')
428
- const stateStore = store.any(subject, ns.wf('stateStore'))
436
+ const stateStore = kb.any(subject, ns.wf('stateStore'))
429
437
  if (!stateStore) throw new Error('This tracker has no stateStore')
430
438
 
431
- authn.checkUser() // kick off async operation
439
+ UI.authn.checkUser() // kick off async operation
432
440
 
433
441
  const h = dom.createElement('h2')
434
442
  h.setAttribute('style', 'font-size: 150%')
@@ -437,7 +445,7 @@ 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
451
  b.setAttribute('style', 'padding: 0.3em; font-size: 100%; margin: 0.5em;')
@@ -454,7 +462,7 @@ export default {
454
462
  'click',
455
463
  function (_event) {
456
464
  b.disabled = true
457
- container.appendChild(newIssueForm(dom, store, tracker, null, showNewIssue))
465
+ container.appendChild(newIssueForm(dom, kb, 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 = store.updater
494
- const t = store.findTypeURIs(subject)
501
+ const updater = kb.updater
502
+ const t = kb.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 (!store.holds(undefined, undefined, undefined, flowOntology)) {
507
+ if (!kb.holds(undefined, undefined, undefined, flowOntology)) {
500
508
  // If not loaded already
501
- $rdf.parse(require('./wf.js'), store, flowOntology.uri, 'text/turtle') // Load ontology directly
509
+ $rdf.parse(require('./wf.js'), kb, flowOntology.uri, 'text/turtle') // Load ontology directly
502
510
  }
503
511
  const userInterfaceOntology = UI.ns.ui('').doc()
504
- if (!store.holds(undefined, undefined, undefined, userInterfaceOntology)) {
512
+ if (!kb.holds(undefined, undefined, undefined, userInterfaceOntology)) {
505
513
  // If not loaded already
506
- $rdf.parse(require('./ui.js'), store, userInterfaceOntology.uri, 'text/turtle') // Load ontology directly
514
+ $rdf.parse(require('./ui.js'), kb, 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
- store.holds(subject, UI.ns.wf('tracker'))
520
+ kb.holds(subject, UI.ns.wf('tracker'))
513
521
  ) {
514
- tracker = store.any(subject, ns.wf('tracker'))
522
+ tracker = kb.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 = store.any(tracker, ns.wf('stateStore'))
530
+ const stateStore = kb.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
- authn.checkUser().then(webId => {
583
+ UI.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.login.loginStatusBox(dom, webIdUri => {
591
+ loginOutButton = UI.authn.loginStatusBox(dom, webIdUri => {
586
592
  if (webIdUri) {
587
- context.me = store.sym(webIdUri)
593
+ context.me = kb.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
@@ -100,7 +100,7 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
100
100
  '</h2><p>Title of new ' +
101
101
  classLabel +
102
102
  ':</p>'
103
- var titlefield = dom.createElement('input')
103
+ const titlefield = dom.createElement('input')
104
104
  titlefield.setAttribute('type', 'text')
105
105
  titlefield.setAttribute(
106
106
  'style',
package/newTracker.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as UI from 'solid-ui'
2
- import { store } from 'solid-logic'
3
2
 
4
3
  const $rdf = UI.rdf
5
4
  const ns = UI.ns
6
- const updater = store.updater
5
+ const kb = UI.store
6
+ const updater = kb.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.login.newAppInstance(context.dom, { noun: 'tracker' }, function (
19
+ const button = UI.authn.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 kb.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 store = context.session.store
39
+ const kb = context.session.store
27
40
 
28
41
  if (!base) {
29
- base = store.any(ws, sp('uriPrefix')).value
42
+ base = kb.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 = store.any(thisTracker, ns.wf('stateStore'))
43
- const newStore = store.sym(base + 'store.ttl')
55
+ const stateStore = kb.any(thisTracker, ns.wf('stateStore'))
56
+ const newStore = kb.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
- const 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 store.sym(u)
60
- }
61
62
  const there = morph(here)
62
63
  const newTracker = morph(thisTracker)
63
64
 
64
- const myConfig = store.statementsMatching(
65
+ const myConfig = kb.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
- store.add(
73
+ kb.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
- store.add(newTracker, UI.ns.space('inspiration'), thisTracker, stateStore)
83
+ kb.add(newTracker, UI.ns.space('inspiration'), thisTracker, stateStore)
83
84
 
84
- store.add(newTracker, UI.ns.space('inspiration'), thisTracker, there)
85
+ kb.add(newTracker, UI.ns.space('inspiration'), thisTracker, there)
85
86
 
86
87
  // $rdf.log.debug("\n Ready to put " + kb.statementsMatching(undefined, undefined, undefined, there)); //@@
87
88
 
88
89
  updater.put(
89
90
  there,
90
- store.statementsMatching(undefined, undefined, undefined, there),
91
+ kb.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-5fd734ff",
3
+ "version": "2.4.9-e1b104be",
4
4
  "description": "Solid-compatible Panes: issue editor",
5
5
  "main": "./issuePane.js",
6
6
  "scripts": {
@@ -34,10 +34,9 @@
34
34
  },
35
35
  "homepage": "https://github.com/solid/issue-pane",
36
36
  "dependencies": {
37
- "pane-registry": "2.4.6-7ecb64b0",
37
+ "pane-registry": "^2.4.6",
38
38
  "rdflib": "^2.2.17",
39
- "solid-logic": "1.3.13-60e05a84",
40
- "solid-ui": "2.4.16-74e478b4"
39
+ "solid-ui": "^2.4.15"
41
40
  },
42
41
  "devDependencies": {
43
42
  "eslint": "^7.32.0",