issue-pane 2.4.10 → 2.4.11
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 +3 -2
- package/.github/workflows/ci.yml +0 -1
- package/.nvmrc +1 -1
- package/board.js +7 -8
- package/issue.js +117 -108
- package/issuePane.js +129 -145
- package/newIssue.js +18 -23
- package/newTracker.js +22 -21
- package/package.json +8 -8
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
|
}
|
package/.github/workflows/ci.yml
CHANGED
package/.nvmrc
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
v16.14.0
|
package/board.js
CHANGED
|
@@ -10,10 +10,9 @@
|
|
|
10
10
|
* @returns dom:Element
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
import { ns, rdf, utils, widgets } from 'solid-ui'
|
|
14
14
|
import { store } from 'solid-logic'
|
|
15
|
-
const
|
|
16
|
-
const $rdf = UI.rdf
|
|
15
|
+
const $rdf = rdf
|
|
17
16
|
|
|
18
17
|
export function board (dom, columnValues, renderItem, options) {
|
|
19
18
|
const board = dom.createElement('div')
|
|
@@ -27,7 +26,7 @@ export function board (dom, columnValues, renderItem, options) {
|
|
|
27
26
|
const mainRow = table.appendChild(dom.createElement('tr'))
|
|
28
27
|
columnValues.forEach(x => {
|
|
29
28
|
const cell = headerRow.appendChild(dom.createElement('th'))
|
|
30
|
-
cell.textContent =
|
|
29
|
+
cell.textContent = utils.label(x, true) // Initial capital
|
|
31
30
|
cell.subject = x
|
|
32
31
|
cell.style = 'margin: 0.3em; padding: 0.5em 1em; font-treatment: bold; font-size: 120%;'
|
|
33
32
|
|
|
@@ -44,7 +43,7 @@ export function board (dom, columnValues, renderItem, options) {
|
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
if (options.columnDropHandler) {
|
|
47
|
-
|
|
46
|
+
widgets.makeDropTarget(column, droppedURIHandler)
|
|
48
47
|
}
|
|
49
48
|
})
|
|
50
49
|
|
|
@@ -57,7 +56,7 @@ export function board (dom, columnValues, renderItem, options) {
|
|
|
57
56
|
const classes = store.each(item, ns.rdf('type'))
|
|
58
57
|
const catColors = classes.map(cat => store.any(cat, ns.ui('backgroundColor'))).filter(c => c)
|
|
59
58
|
|
|
60
|
-
table.appendChild(
|
|
59
|
+
table.appendChild(widgets.personTR(dom, null, item))
|
|
61
60
|
table.subject = item
|
|
62
61
|
table.style = 'margin: 1em;' // @@ use style.js
|
|
63
62
|
const backgroundColor = catColors[0] || store.any(category, ns.ui('backgroundColor'))
|
|
@@ -76,7 +75,7 @@ export function board (dom, columnValues, renderItem, options) {
|
|
|
76
75
|
const actualRenderItem = renderItem || options.renderItem || defaultRenderItem
|
|
77
76
|
function localRenderItem (subject) {
|
|
78
77
|
const ele = actualRenderItem(subject)
|
|
79
|
-
|
|
78
|
+
widgets.makeDraggable(ele, subject)
|
|
80
79
|
ele.subject = subject
|
|
81
80
|
return ele
|
|
82
81
|
}
|
|
@@ -88,7 +87,7 @@ export function board (dom, columnValues, renderItem, options) {
|
|
|
88
87
|
items = items.filter(options.filter)
|
|
89
88
|
}
|
|
90
89
|
const sortedItems = sortedBy(items, sortBy, now, true)
|
|
91
|
-
|
|
90
|
+
utils.syncTableToArrayReOrdered(col, sortedItems, localRenderItem)
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
|
package/issue.js
CHANGED
|
@@ -5,20 +5,33 @@ import { authn, store } from 'solid-logic'
|
|
|
5
5
|
import { newIssueForm } from './newIssue'
|
|
6
6
|
|
|
7
7
|
const $rdf = rdf
|
|
8
|
+
const kb = store
|
|
8
9
|
|
|
9
10
|
const SET_MODIFIED_DATES = false
|
|
10
11
|
|
|
12
|
+
export const TASK_ICON = icons.iconBase + 'noun_17020_gray-tick.svg'
|
|
13
|
+
export const OPEN_TASK_ICON = icons.iconBase + 'noun_17020_sans-tick.svg'
|
|
14
|
+
export const CLOSED_TASK_ICON = icons.iconBase + 'noun_17020.svg'
|
|
15
|
+
|
|
11
16
|
function complain (message, context) {
|
|
12
17
|
console.warn(message)
|
|
13
18
|
context.paneDiv.appendChild(widgets.errorMessageBlock(context.dom, message))
|
|
14
19
|
}
|
|
15
20
|
|
|
21
|
+
export function isOpen (issue) {
|
|
22
|
+
const types = kb.findTypeURIs(issue)
|
|
23
|
+
return !!types[ns.wf('Open').uri]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function iconForIssue (issue) {
|
|
27
|
+
return isOpen(issue) ? TASK_ICON : CLOSED_TASK_ICON
|
|
28
|
+
}
|
|
16
29
|
export function getState (issue, classification) {
|
|
17
|
-
const tracker =
|
|
18
|
-
const states =
|
|
30
|
+
const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
|
|
31
|
+
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
19
32
|
classification = classification || states
|
|
20
|
-
const types =
|
|
21
|
-
.filter(ty =>
|
|
33
|
+
const types = kb.each(issue, ns.rdf('type'))
|
|
34
|
+
.filter(ty => kb.holds(ty, ns.rdfs('subClassOf'), classification))
|
|
22
35
|
if (types.length !== 1) {
|
|
23
36
|
// const initialState = kb.any(tracker, ns.wf('initialState')) No do NOT default
|
|
24
37
|
// if (initialState) return initialState
|
|
@@ -27,26 +40,27 @@ export function getState (issue, classification) {
|
|
|
27
40
|
return types[0]
|
|
28
41
|
}
|
|
29
42
|
|
|
30
|
-
export function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const catColors = classes.map(cat => store.any(cat, ns.ui('backgroundColor'))).filter(c => !!c)
|
|
43
|
+
export function getBackgroundColorFromTypes (issue) {
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
if (catColors.length) return catColors[0].value // pick first one
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function renderIssueCard (issue, context) {
|
|
38
52
|
function refresh () {
|
|
39
|
-
const backgroundColor =
|
|
53
|
+
const backgroundColor = getBackgroundColorFromTypes(issue) || 'white'
|
|
40
54
|
card.style.backgroundColor = backgroundColor
|
|
41
55
|
editButton.style.backgroundColor = backgroundColor // Override white from style sheet
|
|
42
56
|
}
|
|
43
57
|
const dom = context.dom
|
|
44
|
-
const uncategorized = !
|
|
58
|
+
const uncategorized = !getBackgroundColorFromTypes(issue) // This is a suspect issue. Prompt to delete it
|
|
45
59
|
|
|
46
60
|
const card = dom.createElement('div')
|
|
47
61
|
const table = card.appendChild(dom.createElement('table'))
|
|
48
62
|
table.style.width = '100%'
|
|
49
|
-
const options = { draggable: false } // Let the
|
|
63
|
+
const options = { draggable: false } // Let the board make the whole card draggable
|
|
50
64
|
table.appendChild(widgets.personTR(dom, null, issue, options))
|
|
51
65
|
table.subject = issue
|
|
52
66
|
card.style = 'border-radius: 0.4em; border: 0.05em solid grey; margin: 0.3em;'
|
|
@@ -66,7 +80,7 @@ export function renderIssueCard (issue, context) {
|
|
|
66
80
|
if (uncategorized) {
|
|
67
81
|
const deleteButton = widgets.deleteButtonWithCheck(dom, buttonsCell, 'issue', async function () { // noun?
|
|
68
82
|
try {
|
|
69
|
-
await
|
|
83
|
+
await kb.updater.update(kb.connectedStatements(issue))
|
|
70
84
|
} catch (err) {
|
|
71
85
|
complain(`Unable to delete issue: ${err}`, context)
|
|
72
86
|
}
|
|
@@ -100,18 +114,24 @@ export function exposeOverlay (subject, context) {
|
|
|
100
114
|
overlay.firstChild.style.overflow = 'auto' // was scroll
|
|
101
115
|
}
|
|
102
116
|
|
|
117
|
+
function renderSpacer (dom, backgroundColor) {
|
|
118
|
+
const spacer = dom.createElement('div')
|
|
119
|
+
spacer.setAttribute('style', 'height: 1em; margin: 0.5em;') // spacer and placeHolder
|
|
120
|
+
spacer.style.backgroundColor = backgroundColor // try that
|
|
121
|
+
return spacer
|
|
122
|
+
}
|
|
123
|
+
|
|
103
124
|
export function renderIssue (issue, context) {
|
|
104
125
|
// Don't bother changing the last modified dates of things: save time
|
|
105
|
-
function setModifiedDate (subj,
|
|
126
|
+
function setModifiedDate (subj, kb, doc) {
|
|
106
127
|
if (SET_MODIFIED_DATES) {
|
|
107
128
|
if (!getOption(tracker, 'trackLastModified')) return
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
129
|
+
const deletions = kb.statementsMatching(issue, ns.dct('modified'))
|
|
130
|
+
.concat(kb.statementsMatching(issue, ns.wf('modifiedBy'))
|
|
131
|
+
)
|
|
112
132
|
const insertions = [$rdf.st(issue, ns.dct('modified'), new Date(), doc)]
|
|
113
133
|
if (me) insertions.push($rdf.st(issue, ns.wf('modifiedBy'), me, doc))
|
|
114
|
-
|
|
134
|
+
kb.updater.update(deletions, insertions, function (_uri, _ok, _body) {})
|
|
115
135
|
}
|
|
116
136
|
}
|
|
117
137
|
|
|
@@ -123,7 +143,7 @@ export function renderIssue (issue, context) {
|
|
|
123
143
|
return pre
|
|
124
144
|
}
|
|
125
145
|
|
|
126
|
-
|
|
146
|
+
function timestring () {
|
|
127
147
|
const now = new Date()
|
|
128
148
|
return '' + now.getTime()
|
|
129
149
|
// http://www.w3schools.com/jsref/jsref_obj_date.asp
|
|
@@ -144,52 +164,50 @@ export function renderIssue (issue, context) {
|
|
|
144
164
|
}
|
|
145
165
|
function getOption (tracker, option) {
|
|
146
166
|
// eg 'allowSubIssues'
|
|
147
|
-
const opt =
|
|
167
|
+
const opt = kb.any(tracker, ns.ui(option))
|
|
148
168
|
return !!(opt && opt.value)
|
|
149
169
|
}
|
|
150
170
|
|
|
151
171
|
function setPaneStyle () {
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
for (const uri in types) {
|
|
156
|
-
backgroundColor = store.any(
|
|
157
|
-
store.sym(uri),
|
|
158
|
-
store.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 + '; '
|
|
172
|
+
const backgroundColor = getBackgroundColorFromTypes(issue) || '#eee' // default grey
|
|
173
|
+
const mystyle0 = 'padding: 0.5em 1.5em 1em 1.5em; border: 0.7em;'
|
|
174
|
+
const mystyle = mystyle0 + 'border-color: ' + backgroundColor + '; '
|
|
164
175
|
issueDiv.setAttribute('style', mystyle)
|
|
176
|
+
issueDiv.style.backgroundColor = 'white'
|
|
165
177
|
}
|
|
166
178
|
|
|
179
|
+
/// ////////////// Body of renderIssue
|
|
180
|
+
|
|
167
181
|
const dom = context.dom
|
|
168
182
|
// eslint-disable-next-line no-use-before-define
|
|
169
|
-
const tracker =
|
|
183
|
+
const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
|
|
170
184
|
if (!tracker) throw new Error('No tracker')
|
|
171
185
|
// eslint-disable-next-line no-use-before-define
|
|
172
|
-
const stateStore =
|
|
186
|
+
const stateStore = kb.any(tracker, ns.wf('stateStore'))
|
|
173
187
|
const store = issue.doc()
|
|
174
188
|
|
|
175
189
|
const issueDiv = dom.createElement('div')
|
|
176
190
|
const me = authn.currentUser()
|
|
191
|
+
const backgroundColor = getBackgroundColorFromTypes(issue) || 'white'
|
|
177
192
|
|
|
178
193
|
setPaneStyle()
|
|
179
194
|
|
|
180
195
|
authn.checkUser() // kick off async operation
|
|
181
196
|
|
|
182
|
-
const
|
|
197
|
+
const iconButton = issueDiv.appendChild(widgets.button(dom, iconForIssue(issue)))
|
|
198
|
+
widgets.makeDraggable(iconButton, issue) // Drag me wherever you need to do stuff with this issue
|
|
199
|
+
|
|
200
|
+
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
183
201
|
if (!states) { throw new Error('This tracker ' + tracker + ' has no issueClass') }
|
|
184
202
|
const select = widgets.makeSelectForCategory(
|
|
185
203
|
dom,
|
|
186
|
-
|
|
204
|
+
kb,
|
|
187
205
|
issue,
|
|
188
206
|
states,
|
|
189
207
|
stateStore,
|
|
190
208
|
function (ok, body) {
|
|
191
209
|
if (ok) {
|
|
192
|
-
setModifiedDate(store,
|
|
210
|
+
setModifiedDate(store, kb, store)
|
|
193
211
|
widgets.refreshTree(issueDiv)
|
|
194
212
|
} else {
|
|
195
213
|
console.log('Failed to change state:\n' + body)
|
|
@@ -198,18 +216,18 @@ export function renderIssue (issue, context) {
|
|
|
198
216
|
)
|
|
199
217
|
issueDiv.appendChild(select)
|
|
200
218
|
|
|
201
|
-
const cats =
|
|
202
|
-
for (
|
|
219
|
+
const cats = kb.each(tracker, ns.wf('issueCategory')) // zero or more
|
|
220
|
+
for (const cat of cats) {
|
|
203
221
|
issueDiv.appendChild(
|
|
204
222
|
widgets.makeSelectForCategory(
|
|
205
223
|
dom,
|
|
206
|
-
|
|
224
|
+
kb,
|
|
207
225
|
issue,
|
|
208
|
-
|
|
226
|
+
cat,
|
|
209
227
|
stateStore,
|
|
210
228
|
function (ok, body) {
|
|
211
229
|
if (ok) {
|
|
212
|
-
setModifiedDate(store,
|
|
230
|
+
setModifiedDate(store, kb, store)
|
|
213
231
|
widgets.refreshTree(issueDiv)
|
|
214
232
|
} else {
|
|
215
233
|
console.log('Failed to change category:\n' + body)
|
|
@@ -253,40 +271,26 @@ export function renderIssue (issue, context) {
|
|
|
253
271
|
wf:Task :creationForm core:coreIsueForm .
|
|
254
272
|
`
|
|
255
273
|
const CORE_ISSUE_FORM = ns.wf('coreIsueForm')
|
|
256
|
-
$rdf.parse(coreIssueFormText,
|
|
257
|
-
widgets.appendForm(
|
|
274
|
+
$rdf.parse(coreIssueFormText, kb, CORE_ISSUE_FORM.doc().uri, 'text/turtle')
|
|
275
|
+
const form = widgets.appendForm(
|
|
258
276
|
dom,
|
|
259
|
-
|
|
277
|
+
null, // was: container
|
|
260
278
|
{},
|
|
261
279
|
issue,
|
|
262
280
|
CORE_ISSUE_FORM,
|
|
263
281
|
stateStore,
|
|
264
282
|
complainIfBad
|
|
265
283
|
)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
/*
|
|
269
|
-
issueDiv.appendChild(
|
|
270
|
-
widgets.makeDescription(
|
|
271
|
-
dom,
|
|
272
|
-
kb,
|
|
273
|
-
issue,
|
|
274
|
-
ns.wf('description'),
|
|
275
|
-
store,
|
|
276
|
-
function (ok, body) {
|
|
277
|
-
if (ok) setModifiedDate(store, kb, store)
|
|
278
|
-
else console.log('Failed to change description:\n' + body)
|
|
279
|
-
}
|
|
280
|
-
)
|
|
281
|
-
) */
|
|
284
|
+
issueDiv.appendChild(form)
|
|
285
|
+
form.style.backgroundColor = backgroundColor
|
|
282
286
|
|
|
283
287
|
// Assigned to whom?
|
|
284
288
|
|
|
285
|
-
const assignments =
|
|
289
|
+
const assignments = kb.statementsMatching(issue, ns.wf('assignee'))
|
|
286
290
|
if (assignments.length > 1) {
|
|
287
291
|
say('Weird, was assigned to more than one person. Fixing ..')
|
|
288
292
|
const deletions = assignments.slice(1)
|
|
289
|
-
|
|
293
|
+
kb.updater.update(deletions, [], function (uri, ok, body) {
|
|
290
294
|
if (ok) {
|
|
291
295
|
say('Now fixed.')
|
|
292
296
|
} else {
|
|
@@ -299,20 +303,16 @@ export function renderIssue (issue, context) {
|
|
|
299
303
|
// Anyone assigned to any issue we know about
|
|
300
304
|
|
|
301
305
|
async function getPossibleAssignees () {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const group = devGroups[i]
|
|
306
|
-
await store.fetcher.load()
|
|
307
|
-
devs = devs.concat(store.each(group, ns.vcard('member')))
|
|
308
|
-
}
|
|
306
|
+
const devGroups = kb.each(issue, ns.wf('assigneeGroup'))
|
|
307
|
+
await kb.fetcher.load(devGroups) // Load them all
|
|
308
|
+
const groupDevs = devGroups.map(group => kb.each(group, ns.vcard('member'), null, group.doc())).flat()
|
|
309
309
|
// Anyone who is a developer of any project which uses this tracker
|
|
310
|
-
const proj =
|
|
310
|
+
const proj = kb.any(null, ns.doap('bug-database'), tracker) // What project?
|
|
311
311
|
if (proj) {
|
|
312
|
-
await
|
|
313
|
-
devs = devs.concat(store.each(proj, ns.doap('developer')))
|
|
312
|
+
await kb.fetcher.load(proj)
|
|
314
313
|
}
|
|
315
|
-
|
|
314
|
+
const projectDevs = proj ? kb.each(proj, ns.doap('developer')) : []
|
|
315
|
+
return groupDevs.concat(projectDevs)
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
// Super issues first - like parent directories .. maybe use breadcrums from?? @@
|
|
@@ -324,7 +324,7 @@ export function renderIssue (issue, context) {
|
|
|
324
324
|
getPossibleAssignees().then(devs => {
|
|
325
325
|
if (devs.length) {
|
|
326
326
|
devs.forEach(function (person) {
|
|
327
|
-
|
|
327
|
+
kb.fetcher.lookUpThing(person)
|
|
328
328
|
}) // best effort async for names etc
|
|
329
329
|
const opts = {
|
|
330
330
|
// 'mint': '** Add new person **',
|
|
@@ -339,14 +339,14 @@ export function renderIssue (issue, context) {
|
|
|
339
339
|
issueDiv.appendChild(
|
|
340
340
|
widgets.makeSelectForOptions(
|
|
341
341
|
dom,
|
|
342
|
-
|
|
342
|
+
kb,
|
|
343
343
|
issue,
|
|
344
344
|
ns.wf('assignee'),
|
|
345
345
|
devs,
|
|
346
346
|
opts,
|
|
347
347
|
store,
|
|
348
348
|
function (ok, body) {
|
|
349
|
-
if (ok) setModifiedDate(store,
|
|
349
|
+
if (ok) setModifiedDate(store, kb, store)
|
|
350
350
|
else console.log('Failed to change assignee:\n' + body)
|
|
351
351
|
}
|
|
352
352
|
)
|
|
@@ -354,27 +354,36 @@ export function renderIssue (issue, context) {
|
|
|
354
354
|
}
|
|
355
355
|
})
|
|
356
356
|
|
|
357
|
-
/* The trees of super
|
|
357
|
+
/* The trees of super-issues and sub-issues
|
|
358
358
|
*/
|
|
359
|
-
|
|
359
|
+
function supersOver (issue, stack) {
|
|
360
|
+
stack = stack || []
|
|
361
|
+
const sup = kb.any(null, ns.wf('dependent'), issue, issue.doc())
|
|
362
|
+
if (sup) return supersOver(sup, [sup].concat(stack))
|
|
363
|
+
return stack
|
|
364
|
+
}
|
|
360
365
|
if (getOption(tracker, 'allowSubIssues')) {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
subIssuePanel.style = 'margin: 1em; padding: 1em;'
|
|
364
|
-
}
|
|
366
|
+
const subIssuePanel = issueDiv.appendChild(dom.createElement('div'))
|
|
367
|
+
subIssuePanel.style = 'margin: 1em; padding: 1em;'
|
|
365
368
|
|
|
366
369
|
subIssuePanel.appendChild(dom.createElement('h4')).textContent = 'Super Issues'
|
|
367
370
|
const listOfSupers = subIssuePanel.appendChild(dom.createElement('div'))
|
|
371
|
+
listOfSupers.style.display = 'flex'
|
|
368
372
|
listOfSupers.refresh = function () {
|
|
369
|
-
|
|
373
|
+
// const supers = kb.each(null, ns.wf('dependent'), issue, issue.doc())
|
|
374
|
+
const supers = supersOver(issue)
|
|
375
|
+
utils.syncTableToArrayReOrdered(listOfSupers, supers, renderSubIssue)
|
|
370
376
|
}
|
|
371
377
|
listOfSupers.refresh()
|
|
372
378
|
|
|
373
379
|
// Sub issues
|
|
374
380
|
subIssuePanel.appendChild(dom.createElement('h4')).textContent = 'Sub Issues'
|
|
375
381
|
const listOfSubs = subIssuePanel.appendChild(dom.createElement('div'))
|
|
382
|
+
listOfSubs.style.display = 'flex'
|
|
383
|
+
listOfSubs.style.flexDirection = 'reverse' // Or center
|
|
376
384
|
listOfSubs.refresh = function () {
|
|
377
|
-
|
|
385
|
+
const subs = kb.each(issue, ns.wf('dependent'), null, issue.doc())
|
|
386
|
+
utils.syncTableToArrayReOrdered(listOfSubs, subs, renderSubIssue)
|
|
378
387
|
}
|
|
379
388
|
listOfSubs.refresh()
|
|
380
389
|
|
|
@@ -387,7 +396,7 @@ export function renderIssue (issue, context) {
|
|
|
387
396
|
b.addEventListener(
|
|
388
397
|
'click',
|
|
389
398
|
function (_event) {
|
|
390
|
-
subIssuePanel.insertBefore(newIssueForm(dom,
|
|
399
|
+
subIssuePanel.insertBefore(newIssueForm(dom, kb, tracker, issue, listOfSubs.refresh), b.nextSibling) // Pop form just after button
|
|
391
400
|
},
|
|
392
401
|
false
|
|
393
402
|
)
|
|
@@ -396,7 +405,7 @@ export function renderIssue (issue, context) {
|
|
|
396
405
|
issueDiv.appendChild(dom.createElement('br'))
|
|
397
406
|
|
|
398
407
|
// Extras are stored centrally to the tracker
|
|
399
|
-
const extrasForm =
|
|
408
|
+
const extrasForm = kb.any(tracker, ns.wf('extrasEntryForm'))
|
|
400
409
|
if (extrasForm) {
|
|
401
410
|
widgets.appendForm(
|
|
402
411
|
dom,
|
|
@@ -407,14 +416,14 @@ export function renderIssue (issue, context) {
|
|
|
407
416
|
stateStore,
|
|
408
417
|
complainIfBad
|
|
409
418
|
)
|
|
419
|
+
// issueDiv.appendChild(renderSpacer(backgroundColor))
|
|
410
420
|
}
|
|
411
421
|
|
|
412
422
|
// Comment/discussion area
|
|
413
423
|
|
|
414
|
-
const spacer = issueDiv.appendChild(dom
|
|
415
|
-
spacer.setAttribute('style', 'height: 1em') // spacer and placeHolder
|
|
424
|
+
const spacer = issueDiv.appendChild(renderSpacer(dom, backgroundColor))
|
|
416
425
|
|
|
417
|
-
const template =
|
|
426
|
+
const template = kb.anyValue(tracker, ns.wf('issueURITemplate'))
|
|
418
427
|
/*
|
|
419
428
|
var chatDocURITemplate = kb.anyValue(tracker, ns.wf('chatDocURITemplate')) // relaive to issue
|
|
420
429
|
var chat
|
|
@@ -427,20 +436,21 @@ export function renderIssue (issue, context) {
|
|
|
427
436
|
if (template) {
|
|
428
437
|
messageStore = issue.doc() // for now. Could go deeper
|
|
429
438
|
} else {
|
|
430
|
-
messageStore =
|
|
431
|
-
if (!messageStore) messageStore =
|
|
432
|
-
|
|
439
|
+
messageStore = kb.any(tracker, ns.wf('messageStore'))
|
|
440
|
+
if (!messageStore) messageStore = kb.any(tracker, ns.wf('stateStore'))
|
|
441
|
+
kb.sym(messageStore.uri + '#' + 'Chat' + timestring()) // var chat =
|
|
433
442
|
}
|
|
434
443
|
|
|
435
|
-
|
|
444
|
+
kb.fetcher.nowOrWhenFetched(messageStore, function (ok, body, _xhr) {
|
|
436
445
|
if (!ok) {
|
|
437
446
|
const er = dom.createElement('p')
|
|
438
447
|
er.textContent = body // @@ use nice error message
|
|
439
448
|
issueDiv.insertBefore(er, spacer)
|
|
440
449
|
} else {
|
|
441
|
-
const discussion = messageArea(dom,
|
|
450
|
+
const discussion = messageArea(dom, kb, issue, messageStore)
|
|
442
451
|
issueDiv.insertBefore(discussion, spacer)
|
|
443
|
-
|
|
452
|
+
issueDiv.insertBefore(renderSpacer(dom, backgroundColor), discussion)
|
|
453
|
+
} // Not sure why e stuck this in upwards rather than downwards
|
|
444
454
|
})
|
|
445
455
|
|
|
446
456
|
// Draggable attachment list
|
|
@@ -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
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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:
|
|
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
|
|
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
|
|
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
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
**
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import { create, login, ns, icons, rdf, tabs, table, utils, widgets } from 'solid-ui'
|
|
9
9
|
import { store, authn } from 'solid-logic'
|
|
10
10
|
import { board } from './board' // @@ will later be in solid-UI
|
|
11
11
|
import { renderIssue, renderIssueCard, getState, exposeOverlay } from './issue'
|
|
@@ -14,9 +14,8 @@ import { newIssueForm } from './newIssue'
|
|
|
14
14
|
import { trackerSettingsFormText } from './trackerSettingsForm.js'
|
|
15
15
|
// import { trackerInstancesFormText } from './trackerInstancesForm.js'
|
|
16
16
|
|
|
17
|
-
const $rdf =
|
|
18
|
-
const
|
|
19
|
-
const widgets = UI.widgets
|
|
17
|
+
const $rdf = rdf
|
|
18
|
+
const kb = store
|
|
20
19
|
|
|
21
20
|
// const MY_TRACKERS_ICON = UI.icons.iconBase + 'noun_Document_998605.svg'
|
|
22
21
|
// const TRACKER_ICON = UI.icons.iconBase + 'noun_list_638112'
|
|
@@ -24,7 +23,7 @@ const widgets = UI.widgets
|
|
|
24
23
|
|
|
25
24
|
const OVERFLOW_STYLE = 'position: fixed; z-index: 100; top: 1.51em; right: 2em; left: 2em; bottom:1.5em; border: 0.1em grey; overflow: scroll;'
|
|
26
25
|
export default {
|
|
27
|
-
icon:
|
|
26
|
+
icon: icons.iconBase + 'noun_122196.svg', // was: js/panes/issue/tbl-bug-22.png
|
|
28
27
|
// noun_list_638112 is a checklist document
|
|
29
28
|
// noun_Document_998605.svg is a stack of twpo checklists
|
|
30
29
|
// noun_97839.svg is a ladybug
|
|
@@ -36,10 +35,10 @@ export default {
|
|
|
36
35
|
|
|
37
36
|
// Does the subject deserve an issue pane?
|
|
38
37
|
label: function (subject, _context) {
|
|
39
|
-
const t =
|
|
38
|
+
const t = kb.findTypeURIs(subject)
|
|
40
39
|
if (
|
|
41
40
|
t['http://www.w3.org/2005/01/wf/flow#Task'] ||
|
|
42
|
-
|
|
41
|
+
kb.holds(subject, ns.wf('tracker'))
|
|
43
42
|
) { return 'issue' } // in case ontology not available
|
|
44
43
|
if (t['http://www.w3.org/2005/01/wf/flow#Tracker']) return 'tracker'
|
|
45
44
|
// Later: Person. For a list of things assigned to them,
|
|
@@ -61,8 +60,7 @@ export default {
|
|
|
61
60
|
return Promise.all(updates)
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
const ns = UI.ns
|
|
63
|
+
const kb = context.session.store
|
|
66
64
|
let stateStore
|
|
67
65
|
if (options.newInstance) {
|
|
68
66
|
stateStore = kb.sym(options.newInstance.doc().uri + '_state.ttl')
|
|
@@ -94,13 +92,13 @@ export default {
|
|
|
94
92
|
try {
|
|
95
93
|
await updateMany([], ins)
|
|
96
94
|
} catch (err) {
|
|
97
|
-
return
|
|
95
|
+
return widgets.complain(context, 'Error writing tracker configuration: ' + err)
|
|
98
96
|
}
|
|
99
97
|
/*
|
|
100
98
|
try {
|
|
101
99
|
await kb.updater.updateMany([], kb.statementsMatching(undefined, undefined, undefined, stateStore))
|
|
102
100
|
} catch (err) {
|
|
103
|
-
return
|
|
101
|
+
return widgets.complain(context, 'Error writing tracker state file: ' + err)
|
|
104
102
|
}
|
|
105
103
|
*/
|
|
106
104
|
const dom = context.dom
|
|
@@ -126,7 +124,7 @@ export default {
|
|
|
126
124
|
|
|
127
125
|
function complain (message) {
|
|
128
126
|
console.warn(message)
|
|
129
|
-
paneDiv.appendChild(
|
|
127
|
+
paneDiv.appendChild(widgets.errorMessageBlock(dom, message))
|
|
130
128
|
}
|
|
131
129
|
|
|
132
130
|
function complainIfBad (ok, message) {
|
|
@@ -140,83 +138,78 @@ export default {
|
|
|
140
138
|
** This is would not be needed if our quey language
|
|
141
139
|
** allowed is to query ardf Collection membership.
|
|
142
140
|
*/
|
|
143
|
-
async function fixSubClasses (kb, tracker) {
|
|
141
|
+
async function fixSubClasses (kb, tracker) { // 20220228
|
|
144
142
|
async function checkOneSuperclass (klass) {
|
|
145
143
|
const collection = kb.any(klass, ns.owl('disjointUnionOf'), null, doc)
|
|
146
144
|
if (!collection) throw new Error(`Classification ${klass} has no disjointUnionOf`)
|
|
147
145
|
if (!collection.elements) throw new Error(`Classification ${klass} has no array`)
|
|
148
146
|
const needed = new Set(collection.elements.map(x => x.uri))
|
|
149
|
-
const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, doc)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (!existing.has(sub)) {
|
|
158
|
-
insertables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc))
|
|
159
|
-
}
|
|
160
|
-
}
|
|
147
|
+
const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, doc).map(x => x.uri))
|
|
148
|
+
|
|
149
|
+
const superfluous = [...existing].filter(sub => !needed.has(sub))
|
|
150
|
+
const deleteActions = superfluous.map(sub => { return { action: 'delete', st: $rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc) } })
|
|
151
|
+
|
|
152
|
+
const missing = [...needed].filter(sub => !existing.has(sub))
|
|
153
|
+
const insertActions = missing.map(sub => { return { action: 'insert', st: $rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc) } })
|
|
154
|
+
return deleteActions.concat(insertActions)
|
|
161
155
|
}
|
|
162
156
|
const doc = tracker.doc()
|
|
163
157
|
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
164
|
-
const cats = kb.each(tracker, ns.wf('issueCategory'))
|
|
165
|
-
|
|
166
|
-
var deletables = []
|
|
167
|
-
cats.push(states)
|
|
158
|
+
const cats = kb.each(tracker, ns.wf('issueCategory')).concat([states])
|
|
159
|
+
let damage = [] // to make totally functionaly need to deal with map over async.
|
|
168
160
|
for (const klass of cats) {
|
|
169
|
-
await checkOneSuperclass(klass)
|
|
161
|
+
damage = damage.concat(await checkOneSuperclass(klass))
|
|
170
162
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
163
|
+
if (damage.length) {
|
|
164
|
+
const insertables = damage.filter(fix => fix.action === 'insert').map(fix => fix.st)
|
|
165
|
+
const deletables = damage.filter(fix => fix.action === 'delete').map(fix => fix.st)
|
|
166
|
+
// alert(`Internal error: s${damage} subclasses inconsistences!`)
|
|
167
|
+
console.log('Damage:', damage)
|
|
175
168
|
if (confirm(`Fix ${damage} inconsistent subclasses in tracker config?`)) {
|
|
176
169
|
await kb.updater.update(deletables, insertables)
|
|
177
|
-
|
|
170
|
+
}
|
|
178
171
|
}
|
|
179
172
|
}
|
|
180
173
|
|
|
181
174
|
/** /////////////////////////// Board
|
|
182
175
|
*/
|
|
183
176
|
function renderBoard (tracker, klass) {
|
|
184
|
-
const states =
|
|
177
|
+
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
185
178
|
klass = klass || states // default to states
|
|
186
179
|
const doingStates = klass.sameTerm(states)
|
|
187
180
|
|
|
188
181
|
// These are states we will show by default: the open issues.
|
|
189
|
-
const stateArray =
|
|
182
|
+
const stateArray = kb.any(klass, ns.owl('disjointUnionOf'))
|
|
190
183
|
if (!stateArray) {
|
|
191
184
|
return complain(`Configuration error: state ${states} does not have substates`)
|
|
192
185
|
}
|
|
193
186
|
let columnValues = stateArray.elements
|
|
194
187
|
if (doingStates && columnValues.length > 2 // and there are more than two
|
|
195
188
|
) { // strip out closed states
|
|
196
|
-
columnValues = columnValues.filter(state =>
|
|
189
|
+
columnValues = columnValues.filter(state => kb.holds(state, ns.rdfs('subClassOf'), ns.wf('Open')) || state.sameTerm(ns.wf('Open')))
|
|
197
190
|
}
|
|
198
191
|
|
|
199
192
|
async function columnDropHandler (issue, newState) {
|
|
200
193
|
const currentState = getState(issue, klass)
|
|
201
|
-
const tracker =
|
|
202
|
-
const stateStore =
|
|
194
|
+
const tracker = kb.the(issue, ns.wf('tracker'), null, issue.doc())
|
|
195
|
+
const stateStore = kb.any(tracker, ns.wf('stateStore'))
|
|
203
196
|
|
|
204
197
|
if (newState.sameTerm(currentState)) {
|
|
205
|
-
// alert('Same state ' +
|
|
198
|
+
// alert('Same state ' + utils.label(currentState)) // @@ remove
|
|
206
199
|
return
|
|
207
200
|
}
|
|
208
201
|
try {
|
|
209
|
-
await
|
|
202
|
+
await kb.updater.update(
|
|
210
203
|
[$rdf.st(issue, ns.rdf('type'), currentState, stateStore)],
|
|
211
204
|
[$rdf.st(issue, ns.rdf('type'), newState, stateStore)])
|
|
212
205
|
} catch (err) {
|
|
213
|
-
|
|
206
|
+
widgets.complain(context, 'Unable to change issue state: ' + err)
|
|
214
207
|
}
|
|
215
208
|
boardDiv.refresh() // reorganize board to match the new reality
|
|
216
209
|
}
|
|
217
210
|
|
|
218
211
|
function isOpen (issue) {
|
|
219
|
-
const types =
|
|
212
|
+
const types = kb.findTypeURIs(issue)
|
|
220
213
|
return !!types[ns.wf('Open').uri]
|
|
221
214
|
}
|
|
222
215
|
|
|
@@ -234,15 +227,15 @@ export default {
|
|
|
234
227
|
/** ////////////// Table
|
|
235
228
|
*/
|
|
236
229
|
function tableRefreshButton (stateStore, tableDiv) {
|
|
237
|
-
const refreshButton = widgets.button(dom,
|
|
230
|
+
const refreshButton = widgets.button(dom, icons.iconBase + 'noun_479395.svg',
|
|
238
231
|
'refresh table', async _event => {
|
|
239
232
|
try {
|
|
240
|
-
await
|
|
233
|
+
await kb.fetcher.load(stateStore, { force: true, clearPreviousData: true })
|
|
241
234
|
} catch (err) {
|
|
242
235
|
alert(err)
|
|
243
236
|
return
|
|
244
237
|
}
|
|
245
|
-
|
|
238
|
+
widgets.refreshTree(tableDiv)
|
|
246
239
|
})
|
|
247
240
|
return refreshButton
|
|
248
241
|
}
|
|
@@ -253,10 +246,10 @@ export default {
|
|
|
253
246
|
query.pat.optional.push(clause)
|
|
254
247
|
return clause
|
|
255
248
|
}
|
|
256
|
-
const states =
|
|
257
|
-
const cats =
|
|
249
|
+
const states = kb.any(subject, ns.wf('issueClass'))
|
|
250
|
+
const cats = kb.each(tracker, ns.wf('issueCategory')) // zero or more
|
|
258
251
|
const vars = ['issue', 'state', 'created']
|
|
259
|
-
|
|
252
|
+
const query = new $rdf.Query(utils.label(subject))
|
|
260
253
|
for (let i = 0; i < cats.length; i++) {
|
|
261
254
|
vars.push('_cat_' + i)
|
|
262
255
|
}
|
|
@@ -278,7 +271,7 @@ export default {
|
|
|
278
271
|
clause.add(v['_cat_' + i], ns.rdfs('subClassOf'), cats[i])
|
|
279
272
|
}
|
|
280
273
|
|
|
281
|
-
const propertyList =
|
|
274
|
+
const propertyList = kb.any(tracker, ns.wf('propertyList')) // List of extra properties
|
|
282
275
|
if (propertyList) {
|
|
283
276
|
const properties = propertyList.elements
|
|
284
277
|
for (let p = 0; p < properties.length; p++) {
|
|
@@ -294,10 +287,10 @@ export default {
|
|
|
294
287
|
}
|
|
295
288
|
|
|
296
289
|
const selectedStates = {}
|
|
297
|
-
const possible =
|
|
290
|
+
const possible = kb.each(undefined, ns.rdfs('subClassOf'), states)
|
|
298
291
|
possible.forEach(function (s) {
|
|
299
292
|
if (
|
|
300
|
-
|
|
293
|
+
kb.holds(s, ns.rdfs('subClassOf'), ns.wf('Open')) ||
|
|
301
294
|
s.sameTerm(ns.wf('Open'))
|
|
302
295
|
) {
|
|
303
296
|
selectedStates[s.uri] = true
|
|
@@ -310,7 +303,7 @@ export default {
|
|
|
310
303
|
exposeOverlay(subject, context)
|
|
311
304
|
}
|
|
312
305
|
|
|
313
|
-
const tableDiv =
|
|
306
|
+
const tableDiv = table(dom, {
|
|
314
307
|
query: query,
|
|
315
308
|
keyVariable: '?issue', // Charactersic of row
|
|
316
309
|
sortBy: '?created', // By default, sort by date
|
|
@@ -321,7 +314,7 @@ export default {
|
|
|
321
314
|
'?state': { initialSelection: selectedStates, label: 'Status' }
|
|
322
315
|
}
|
|
323
316
|
})
|
|
324
|
-
const stateStore =
|
|
317
|
+
const stateStore = kb.any(subject, ns.wf('stateStore'))
|
|
325
318
|
tableDiv.appendChild(tableRefreshButton(stateStore, tableDiv))
|
|
326
319
|
return tableDiv
|
|
327
320
|
}
|
|
@@ -341,14 +334,14 @@ export default {
|
|
|
341
334
|
}
|
|
342
335
|
const issuePane = context.session.paneRegistry.byName('issue')
|
|
343
336
|
const relevantPanes = [issuePane]
|
|
344
|
-
|
|
337
|
+
create.newThingUI(creationContext, context, relevantPanes) // Have to pass panes down newUI
|
|
345
338
|
return creationDiv
|
|
346
339
|
}
|
|
347
340
|
|
|
348
341
|
function renderInstances (theClass) {
|
|
349
342
|
const instancesDiv = dom.createElement('div')
|
|
350
343
|
const context = { dom, div: instancesDiv, noun: 'tracker' }
|
|
351
|
-
|
|
344
|
+
login.registrationList(context, { public: true, private: true, type: theClass }).then(_context2 => {
|
|
352
345
|
instancesDiv.appendChild(renderCreationControl(instancesDiv))
|
|
353
346
|
/* // keep this code in case we need a form
|
|
354
347
|
const InstancesForm = ns.wf('TrackerInstancesForm')
|
|
@@ -362,12 +355,21 @@ export default {
|
|
|
362
355
|
}
|
|
363
356
|
function renderSettings (tracker) {
|
|
364
357
|
const settingsDiv = dom.createElement('div')
|
|
358
|
+
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
359
|
+
const views = [tableView, states] // Possible default views
|
|
360
|
+
.concat(kb.each(tracker, ns.wf('issueCategory')))
|
|
361
|
+
const box = settingsDiv.appendChild(dom.createElement('div'))
|
|
362
|
+
const lhs = widgets.renderNameValuePair(dom, kb, box, null, 'Default view') // @@ use a predicate?
|
|
363
|
+
lhs.appendChild(widgets.makeSelectForOptions(dom, kb, tracker,
|
|
364
|
+
ns.wf('defaultView'),
|
|
365
|
+
views, {}, tracker.doc()))
|
|
366
|
+
|
|
365
367
|
// A registration control allows the to record this tracker in their type index
|
|
366
368
|
const context = { dom, div: settingsDiv, noun: 'tracker' }
|
|
367
|
-
|
|
369
|
+
login.registrationControl(context, tracker, ns.wf('Tracker')).then(_context2 => {
|
|
368
370
|
const settingsForm = ns.wf('TrackerSettingsForm')
|
|
369
371
|
const text = trackerSettingsFormText
|
|
370
|
-
$rdf.parse(text,
|
|
372
|
+
$rdf.parse(text, kb, settingsForm.doc().uri, 'text/turtle')
|
|
371
373
|
widgets.appendForm(dom, settingsDiv, {}, tracker, settingsForm,
|
|
372
374
|
tracker.doc(), complainIfBad)
|
|
373
375
|
})
|
|
@@ -385,76 +387,103 @@ export default {
|
|
|
385
387
|
ele.appendChild(renderSettings(tracker))
|
|
386
388
|
} else if (object.sameTerm(instancesView)) {
|
|
387
389
|
ele.appendChild(renderInstances(ns.wf('Tracker')))
|
|
388
|
-
} else if ((
|
|
389
|
-
(
|
|
390
|
+
} else if ((kb.holds(tracker, ns.wf('issueCategory'), object)) ||
|
|
391
|
+
(kb.holds(tracker, ns.wf('issueClass'), object))) {
|
|
390
392
|
ele.appendChild(renderBoard(tracker, object))
|
|
391
393
|
} else {
|
|
392
394
|
throw new Error('Unexpected tab type: ' + object)
|
|
393
395
|
}
|
|
394
396
|
}
|
|
395
|
-
const states =
|
|
397
|
+
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
396
398
|
const items = [instancesView, tableView, states]
|
|
397
|
-
.concat(
|
|
399
|
+
.concat(kb.each(tracker, ns.wf('issueCategory')))
|
|
398
400
|
items.push(settingsView)
|
|
399
|
-
const selectedTab = tableView
|
|
401
|
+
const selectedTab = kb.any(tracker, ns.wf('defaultView'), null, tracker.doc()) || tableView
|
|
400
402
|
const options = { renderMain, items, selectedTab }
|
|
401
403
|
|
|
402
404
|
// Add stuff to the ontologies which we believe but they don't say
|
|
403
405
|
const doc = instancesView.doc()
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
406
|
+
kb.add(instancesView, ns.rdfs('label'), 'My Trackers', doc) // @@ squatting on wf ns
|
|
407
|
+
kb.add(settingsView, ns.rdfs('label'), 'Settings', doc) // @@ squatting on wf ns
|
|
408
|
+
kb.add(states, ns.rdfs('label'), 'By State', doc) // @@ squatting on wf ns
|
|
407
409
|
|
|
408
|
-
const
|
|
409
|
-
return
|
|
410
|
+
const myTabs = tabs.tabWidget(options)
|
|
411
|
+
return myTabs
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async function renderSingleIssue () {
|
|
415
|
+
tracker = kb.any(subject, ns.wf('tracker'))
|
|
416
|
+
if (!tracker) throw new Error('This issue ' + subject + 'has no tracker')
|
|
417
|
+
|
|
418
|
+
// Much data is in the tracker instance, so wait for the data from it
|
|
419
|
+
try {
|
|
420
|
+
const _xhrs = await context.session.store.fetcher.load(tracker.doc())
|
|
421
|
+
} catch (err) {
|
|
422
|
+
const msg = 'Failed to load tracker config ' + tracker.doc() + ': ' + err
|
|
423
|
+
return complain(msg)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const stateStore = kb.any(tracker, ns.wf('stateStore'))
|
|
427
|
+
if (!stateStore) {
|
|
428
|
+
return complain('Tracker has no state store: ' + tracker)
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
await context.session.store.fetcher.load(subject)
|
|
432
|
+
} catch (err) {
|
|
433
|
+
return complain('Failed to load issue state ' + stateStore + ': ' + err)
|
|
434
|
+
}
|
|
435
|
+
paneDiv.appendChild(renderIssue(subject, context))
|
|
436
|
+
updater.addDownstreamChangeListener(stateStore, function () {
|
|
437
|
+
widgets.refreshTree(paneDiv)
|
|
438
|
+
}) // Live update
|
|
410
439
|
}
|
|
411
440
|
|
|
412
441
|
async function renderTracker () {
|
|
413
442
|
function showNewIssue (issue) {
|
|
414
|
-
|
|
443
|
+
widgets.refreshTree(paneDiv)
|
|
415
444
|
exposeOverlay(issue, context)
|
|
416
|
-
|
|
445
|
+
newIssueButton.disabled = false // https://stackoverflow.com/questions/41176582/enable-disable-a-button-in-pure-javascript
|
|
417
446
|
}
|
|
418
447
|
tracker = subject
|
|
419
448
|
|
|
420
449
|
try {
|
|
421
|
-
await fixSubClasses(
|
|
450
|
+
await fixSubClasses(kb, tracker)
|
|
422
451
|
} catch (err) {
|
|
423
452
|
console.log('@@@ Error fixing subclasses in config: ' + err)
|
|
424
453
|
}
|
|
425
454
|
|
|
426
|
-
const states =
|
|
455
|
+
const states = kb.any(subject, ns.wf('issueClass'))
|
|
427
456
|
if (!states) throw new Error('This tracker has no issueClass')
|
|
428
|
-
const stateStore =
|
|
457
|
+
const stateStore = kb.any(subject, ns.wf('stateStore'))
|
|
429
458
|
if (!stateStore) throw new Error('This tracker has no stateStore')
|
|
430
459
|
|
|
431
|
-
|
|
460
|
+
// const me = await authn.currentUser()
|
|
432
461
|
|
|
433
462
|
const h = dom.createElement('h2')
|
|
434
463
|
h.setAttribute('style', 'font-size: 150%')
|
|
435
464
|
paneDiv.appendChild(h)
|
|
436
|
-
const classLabel =
|
|
465
|
+
const classLabel = utils.label(states)
|
|
437
466
|
h.appendChild(dom.createTextNode(classLabel + ' list')) // Use class label @@I18n
|
|
438
467
|
|
|
439
468
|
// New Issue button
|
|
440
|
-
|
|
469
|
+
const newIssueButton = dom.createElement('button')
|
|
441
470
|
const container = dom.createElement('div')
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
container.appendChild(
|
|
471
|
+
newIssueButton.setAttribute('type', 'button')
|
|
472
|
+
newIssueButton.setAttribute('style', 'padding: 0.3em; font-size: 100%; margin: 0.5em;')
|
|
473
|
+
container.appendChild(newIssueButton)
|
|
445
474
|
paneDiv.appendChild(container)
|
|
446
475
|
const img = dom.createElement('img')
|
|
447
|
-
img.setAttribute('src',
|
|
476
|
+
img.setAttribute('src', icons.iconBase + 'noun_19460_green.svg')
|
|
448
477
|
img.setAttribute('style', 'width: 1em; height: 1em; margin: 0.2em;')
|
|
449
|
-
|
|
478
|
+
newIssueButton.appendChild(img)
|
|
450
479
|
const span = dom.createElement('span')
|
|
451
480
|
span.innerHTML = 'New ' + classLabel
|
|
452
|
-
|
|
453
|
-
|
|
481
|
+
newIssueButton.appendChild(span)
|
|
482
|
+
newIssueButton.addEventListener(
|
|
454
483
|
'click',
|
|
455
484
|
function (_event) {
|
|
456
|
-
|
|
457
|
-
container.appendChild(newIssueForm(dom,
|
|
485
|
+
newIssueButton.disabled = true
|
|
486
|
+
container.appendChild(newIssueForm(dom, kb, tracker, null, showNewIssue))
|
|
458
487
|
},
|
|
459
488
|
false
|
|
460
489
|
)
|
|
@@ -474,7 +503,7 @@ export default {
|
|
|
474
503
|
} else {
|
|
475
504
|
console.log('No table refresh function?!')
|
|
476
505
|
}
|
|
477
|
-
paneDiv.appendChild(newTrackerButton(subject))
|
|
506
|
+
paneDiv.appendChild(newTrackerButton(subject, context))
|
|
478
507
|
updater.addDownstreamChangeListener(stateStore, tableDiv.refresh) // Live update
|
|
479
508
|
})
|
|
480
509
|
.catch(function (err) {
|
|
@@ -490,73 +519,30 @@ export default {
|
|
|
490
519
|
const settingsView = ns.wf('SettingsView')
|
|
491
520
|
const instancesView = ns.wf('InstancesView')
|
|
492
521
|
|
|
493
|
-
const updater =
|
|
494
|
-
const t =
|
|
522
|
+
const updater = kb.updater
|
|
523
|
+
const t = kb.findTypeURIs(subject)
|
|
495
524
|
let tracker
|
|
496
525
|
|
|
497
526
|
// Whatever we are rendering, lets load the ontology
|
|
498
|
-
const flowOntology =
|
|
499
|
-
if (!
|
|
527
|
+
const flowOntology = ns.wf('').doc()
|
|
528
|
+
if (!kb.holds(undefined, undefined, undefined, flowOntology)) {
|
|
500
529
|
// If not loaded already
|
|
501
|
-
$rdf.parse(require('./wf.js'),
|
|
530
|
+
$rdf.parse(require('./wf.js'), kb, flowOntology.uri, 'text/turtle') // Load ontology directly
|
|
502
531
|
}
|
|
503
|
-
const userInterfaceOntology =
|
|
504
|
-
if (!
|
|
532
|
+
const userInterfaceOntology = ns.ui('').doc()
|
|
533
|
+
if (!kb.holds(undefined, undefined, undefined, userInterfaceOntology)) {
|
|
505
534
|
// If not loaded already
|
|
506
|
-
$rdf.parse(require('./ui.js'),
|
|
535
|
+
$rdf.parse(require('./ui.js'), kb, userInterfaceOntology.uri, 'text/turtle') // Load ontology directly
|
|
507
536
|
}
|
|
508
537
|
|
|
509
538
|
// Render a single issue
|
|
510
539
|
if (
|
|
511
540
|
t['http://www.w3.org/2005/01/wf/flow#Task'] ||
|
|
512
|
-
|
|
541
|
+
kb.holds(subject, ns.wf('tracker'))
|
|
513
542
|
) {
|
|
514
|
-
|
|
515
|
-
if (!tracker) throw new Error('This issue ' + subject + 'has no tracker')
|
|
516
|
-
|
|
517
|
-
// Much data is in the tracker instance, so wait for the data from it
|
|
518
|
-
|
|
519
|
-
context.session.store.fetcher
|
|
520
|
-
.load(tracker.doc())
|
|
521
|
-
.then(function (_xhrs) {
|
|
522
|
-
const stateStore = store.any(tracker, ns.wf('stateStore'))
|
|
523
|
-
context.session.store.fetcher.nowOrWhenFetched(
|
|
524
|
-
stateStore,
|
|
525
|
-
subject,
|
|
526
|
-
function drawIssuePane2 (ok, body) {
|
|
527
|
-
if (!ok) {
|
|
528
|
-
return console.log(
|
|
529
|
-
'Failed to load state ' + stateStore + ' ' + body
|
|
530
|
-
)
|
|
531
|
-
}
|
|
532
|
-
paneDiv.appendChild(renderIssue(subject, context))
|
|
533
|
-
updater.addDownstreamChangeListener(stateStore, function () {
|
|
534
|
-
UI.widgets.refreshTree(paneDiv)
|
|
535
|
-
}) // Live update
|
|
536
|
-
}
|
|
537
|
-
)
|
|
538
|
-
})
|
|
539
|
-
.catch(err => {
|
|
540
|
-
const msg = 'Failed to load config ' + tracker.doc() + ' ' + err
|
|
541
|
-
return complain(msg)
|
|
542
|
-
})
|
|
543
|
-
context.session.store.fetcher.nowOrWhenFetched(
|
|
544
|
-
tracker.doc(),
|
|
545
|
-
subject,
|
|
546
|
-
function drawIssuePane1 (ok, body) {
|
|
547
|
-
if (!ok) {
|
|
548
|
-
return console.log(
|
|
549
|
-
'Failed to load config ' + tracker.doc() + ' ' + body
|
|
550
|
-
)
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
) // End nowOrWhenFetched tracker
|
|
554
|
-
|
|
555
|
-
// /////////////////////////////////////////////////////////
|
|
556
|
-
//
|
|
557
|
-
// Render a Tracker instance
|
|
558
|
-
//
|
|
543
|
+
renderSingleIssue().then(() => console.log('Single issue rendered'))
|
|
559
544
|
} else if (t['http://www.w3.org/2005/01/wf/flow#Tracker']) {
|
|
545
|
+
// Render a Tracker instance
|
|
560
546
|
renderTracker().then(() => console.log('Tracker rendered'))
|
|
561
547
|
} else {
|
|
562
548
|
console.log(
|
|
@@ -572,8 +558,6 @@ export default {
|
|
|
572
558
|
overlay.style = OVERFLOW_STYLE
|
|
573
559
|
overlay.style.visibility = 'hidden'
|
|
574
560
|
|
|
575
|
-
// var overlayPane = null // overlay.appendChild(dom.createElement('div')) // avoid stomping on style by pane
|
|
576
|
-
|
|
577
561
|
authn.checkUser().then(webId => {
|
|
578
562
|
if (webId) {
|
|
579
563
|
console.log('Web ID set already: ' + webId)
|
|
@@ -582,9 +566,9 @@ export default {
|
|
|
582
566
|
return
|
|
583
567
|
}
|
|
584
568
|
|
|
585
|
-
loginOutButton =
|
|
569
|
+
loginOutButton = authn.loginStatusBox(dom, webIdUri => {
|
|
586
570
|
if (webIdUri) {
|
|
587
|
-
context.me =
|
|
571
|
+
context.me = kb.sym(webIdUri)
|
|
588
572
|
console.log('Web ID set from login button: ' + webIdUri)
|
|
589
573
|
paneDiv.removeChild(loginOutButton)
|
|
590
574
|
// enable things
|
package/newIssue.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
// Form to collect data about a New Issue
|
|
2
2
|
//
|
|
3
|
-
import
|
|
3
|
+
import { ns, rdf, utils } from 'solid-ui'
|
|
4
4
|
|
|
5
|
-
const $rdf =
|
|
6
|
-
const ns = UI.ns
|
|
5
|
+
const $rdf = rdf
|
|
7
6
|
|
|
8
7
|
export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
|
|
9
8
|
const form = dom.createElement('div') // form is broken as HTML behaviour can resurface on js error
|
|
@@ -19,7 +18,6 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
|
|
|
19
18
|
titlefield.setAttribute('class', 'pendingedit')
|
|
20
19
|
titlefield.disabled = true
|
|
21
20
|
const sts = []
|
|
22
|
-
let issue
|
|
23
21
|
|
|
24
22
|
const expandTemplate = function (template) {
|
|
25
23
|
const now = new $rdf.Literal(new Date())
|
|
@@ -34,34 +32,30 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
|
|
|
34
32
|
.replace('{DD}', DD)
|
|
35
33
|
}
|
|
36
34
|
// Where to store the new issue?
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if (template) {
|
|
35
|
+
const template = kb.anyValue(tracker, ns.wf('issueURITemplate'))
|
|
36
|
+
const issue = template
|
|
40
37
|
// Does each issue do in its own file?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
// eslint-disable-next-line prefer-const
|
|
47
|
-
issueDoc = issue.doc()
|
|
38
|
+
? kb.sym(expandTemplate($rdf.uri.join(template, stateStore.uri)))
|
|
39
|
+
: kb.sym(stateStore.uri + '#' + 'Iss' + timestring())
|
|
40
|
+
|
|
41
|
+
const issueDoc = issue.doc()
|
|
48
42
|
|
|
49
43
|
// Basic 9 core predicates are stored in the main stateStore
|
|
50
44
|
|
|
51
45
|
const title = kb.literal(titlefield.value)
|
|
52
46
|
sts.push(new $rdf.Statement(issue, ns.wf('tracker'), tracker, stateStore))
|
|
53
47
|
sts.push(new $rdf.Statement(issue, ns.dc('title'), title, stateStore))
|
|
54
|
-
sts.push(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
for (
|
|
48
|
+
sts.push(new $rdf.Statement(issue, ns.dct('created'), new Date(), stateStore))
|
|
49
|
+
// Copy states from super issue as after all they are subtasks so initially same state same category
|
|
50
|
+
const initialStates = superIssue
|
|
51
|
+
? kb.each(superIssue, ns.rdf('type'), null, superIssue.doc())
|
|
52
|
+
: kb.each(tracker, ns.wf('initialState'))
|
|
53
|
+
for (const state of initialStates) {
|
|
60
54
|
sts.push(
|
|
61
55
|
new $rdf.Statement(
|
|
62
56
|
issue,
|
|
63
57
|
ns.rdf('type'),
|
|
64
|
-
|
|
58
|
+
state,
|
|
65
59
|
stateStore
|
|
66
60
|
)
|
|
67
61
|
)
|
|
@@ -92,7 +86,7 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
|
|
|
92
86
|
}
|
|
93
87
|
|
|
94
88
|
const states = kb.any(tracker, ns.wf('issueClass'))
|
|
95
|
-
const classLabel =
|
|
89
|
+
const classLabel = utils.label(states)
|
|
96
90
|
form.innerHTML =
|
|
97
91
|
'<h2>Add new ' +
|
|
98
92
|
(superIssue ? 'sub ' : '') +
|
|
@@ -100,7 +94,7 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
|
|
|
100
94
|
'</h2><p>Title of new ' +
|
|
101
95
|
classLabel +
|
|
102
96
|
':</p>'
|
|
103
|
-
|
|
97
|
+
const titlefield = dom.createElement('input')
|
|
104
98
|
titlefield.setAttribute('type', 'text')
|
|
105
99
|
titlefield.setAttribute(
|
|
106
100
|
'style',
|
|
@@ -119,5 +113,6 @@ export function newIssueForm (dom, kb, tracker, superIssue, showNewIssue) {
|
|
|
119
113
|
false
|
|
120
114
|
)
|
|
121
115
|
form.appendChild(titlefield)
|
|
116
|
+
titlefield.focus() // we want user cursor here
|
|
122
117
|
return form
|
|
123
118
|
}
|
package/newTracker.js
CHANGED
|
@@ -3,6 +3,7 @@ import { store } from 'solid-logic'
|
|
|
3
3
|
|
|
4
4
|
const $rdf = UI.rdf
|
|
5
5
|
const ns = UI.ns
|
|
6
|
+
const kb = store
|
|
6
7
|
const updater = store.updater
|
|
7
8
|
|
|
8
9
|
/* Button for making a whole new tracker
|
|
@@ -20,13 +21,25 @@ export function newTrackerButton (thisTracker, context) {
|
|
|
20
21
|
ws,
|
|
21
22
|
base
|
|
22
23
|
) {
|
|
24
|
+
function morph (x) {
|
|
25
|
+
// Move any URIs in this space into that space
|
|
26
|
+
if (x.elements !== undefined) return x.elements.map(morph) // Morph within lists
|
|
27
|
+
if (x.uri === undefined) return x
|
|
28
|
+
let u = x.uri
|
|
29
|
+
if (u === stateStore.uri) return newStore // special case
|
|
30
|
+
if (u.slice(0, oldBase.length) === oldBase) {
|
|
31
|
+
u = base + u.slice(oldBase.length)
|
|
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
|
|
39
|
+
const kb = context.session.store
|
|
27
40
|
|
|
28
41
|
if (!base) {
|
|
29
|
-
base =
|
|
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 =
|
|
43
|
-
const newStore =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
83
|
+
kb.add(newTracker, UI.ns.space('inspiration'), thisTracker, stateStore)
|
|
83
84
|
|
|
84
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "2.4.11",
|
|
4
4
|
"description": "Solid-compatible Panes: issue editor",
|
|
5
5
|
"main": "./issuePane.js",
|
|
6
6
|
"scripts": {
|
|
@@ -34,16 +34,16 @@
|
|
|
34
34
|
},
|
|
35
35
|
"homepage": "https://github.com/solid/issue-pane",
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"pane-registry": "^2.4.
|
|
38
|
-
"rdflib": "^2.2.
|
|
39
|
-
"solid-logic": "^1.3.
|
|
40
|
-
"solid-ui": "^2.4.
|
|
37
|
+
"pane-registry": "^2.4.9",
|
|
38
|
+
"rdflib": "^2.2.19",
|
|
39
|
+
"solid-logic": "^1.3.16",
|
|
40
|
+
"solid-ui": "^2.4.20"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"eslint": "^
|
|
43
|
+
"eslint": "^8.12.0",
|
|
44
|
+
"eslint-plugin-import": "^2.25.4",
|
|
44
45
|
"husky": "^7.0.4",
|
|
45
|
-
"lint-staged": "^
|
|
46
|
-
"standard": "^16.0.4"
|
|
46
|
+
"lint-staged": "^12.3.7"
|
|
47
47
|
},
|
|
48
48
|
"husky": {
|
|
49
49
|
"hooks": {
|