Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Wrap TTL files into JS files for bundling with library

,all : wf.js trackerSettingsForm.js trackerInstancesForm.js ui.js
# was trackerInstancesForm.js

,all : wf.js trackerSettingsForm.js ui.js

#individualForm.js : individualForm.ttl
# (echo 'module.exports = `' ; cat individualForm.ttl; echo '`') > individualForm.js
Expand Down
30 changes: 8 additions & 22 deletions issue.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function renderIssueCard (issue, context) {
const backgroundColor = getBackgroundColor() || 'white'
card.style.backgroundColor = backgroundColor
editButton.style.backgroundColor = backgroundColor // Override white from style sheet
widgets.setImage(img, issue) // react to a change of class of the object
}
const dom = context.dom
const uncategorized = !getBackgroundColor() // This is a suspect issue. Prompt to delete it
Expand All @@ -52,7 +53,8 @@ export function renderIssueCard (issue, context) {
card.style = 'border-radius: 0.4em; border: 0.05em solid grey; margin: 0.3em;'

const img = card.firstChild.firstChild.firstChild.firstChild // div/table/tr/td/img
img.setAttribute('src', icons.iconBase + 'noun_Danger_1259514.svg') // override
// img.setAttribute('src', icons.iconBase + 'noun_Danger_1259514.svg') // override

// Add a button for viewing the whole issue in overlay
const buttonsCell = card.firstChild.firstChild.children[2] // right hand part of card
const editButton = widgets.button(dom, icons.iconBase + 'noun_253504.svg', 'edit', async _event => {
Expand Down Expand Up @@ -262,22 +264,6 @@ export function renderIssue (issue, context) {
complainIfBad
)

// Descriptions can be long and are stored local to the issue
/*
issueDiv.appendChild(
widgets.makeDescription(
dom,
kb,
issue,
ns.wf('description'),
store,
function (ok, body) {
if (ok) setModifiedDate(store, kb, store)
else console.log('Failed to change description:\n' + body)
}
)
) */

// Assigned to whom?

const assignments = kb.statementsMatching(issue, ns.wf('assignee'))
Expand All @@ -301,8 +287,8 @@ export function renderIssue (issue, context) {
const devGroups = kb.each(issue, ns.wf('assigneeGroup'))
for (let i = 0; i < devGroups.length; i++) {
const group = devGroups[i]
await kb.fetcher.load()
devs = devs.concat(kb.each(group, ns.vcard('member')))
await kb.fetcher.load(group)
devs = devs.concat(kb.each(group, ns.vcard('hasMember')))
}
// Anyone who is a developer of any project which uses this tracker
const proj = kb.any(null, ns.doap('bug-database'), tracker) // What project?
Expand All @@ -321,9 +307,9 @@ export function renderIssue (issue, context) {

getPossibleAssignees().then(devs => {
if (devs.length) {
devs.forEach(function (person) {
kb.fetcher.lookUpThing(person)
}) // best effort async for names etc
// devs.map(function (person) {
// kb.fetcher.lookUpThing(person)
// }) // best effort async for names etc
const opts = {
// 'mint': '** Add new person **',
nullLabel: '(unassigned)'
Expand Down
159 changes: 90 additions & 69 deletions issuePane.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,13 @@ export default {
try {
await updateMany([], ins)
} catch (err) {
return UI.widgets.complain(context, 'Error writing tracker configuration: ' + err)
return widgets.complain(context, 'Error writing tracker configuration: ' + err)
}
/*
try {
await kb.updater.updateMany([], kb.statementsMatching(undefined, undefined, undefined, stateStore))
} catch (err) {
return UI.widgets.complain(context, 'Error writing tracker state file: ' + err)
return widgets.complain(context, 'Error writing tracker state file: ' + err)
}
*/
const dom = context.dom
Expand All @@ -118,15 +118,22 @@ export default {
},

render: function (subject, context) {
function refreshPane () {
for (const ele of refreshables) {
widgets.refreshTree(ele)
}
}
const dom = context.dom

const paneDiv = dom.createElement('div')
context.paneDiv = paneDiv
paneDiv.setAttribute('class', 'issuePane')
var refreshables = [] // Separate of widgets to be refreshed
paneDiv.refresh = refreshPane

function complain (message) {
console.warn(message)
paneDiv.appendChild(UI.widgets.errorMessageBlock(dom, message))
paneDiv.appendChild(widgets.errorMessageBlock(dom, message))
}

function complainIfBad (ok, message) {
Expand All @@ -137,50 +144,63 @@ export default {

/** Infer subclass from disjoint Union
**
** This is would not be needed if our quey language
** allowed is to query ardf Collection membership.
** This is would not be needed if our query language
** allowed is to query rdf Collection membership.
*/
async function fixSubClasses (kb, tracker) {
async function checkOneSuperclass (klass) {
const collection = kb.any(klass, ns.owl('disjointUnionOf'), null, doc)
function checkSubClasses (kb, tracker) {
function checkOneSuperclass (klass) {
const collection = kb.any(klass, ns.owl('disjointUnionOf'), null, klass.doc())
if (!collection) throw new Error(`Classification ${klass} has no disjointUnionOf`)
if (!collection.elements) throw new Error(`Classification ${klass} has no array`)
const needed = new Set(collection.elements.map(x => x.uri))
const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, doc)
const existing = new Set(kb.each(null, ns.rdfs('subClassOf'), klass, klass.doc())
.map(x => x.uri))
for (const sub of existing) {
if (!needed.has(sub)) {
deletables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc))
deletables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, klass.doc()))
}
}
for (const sub of needed) {
if (!existing.has(sub)) {
insertables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, doc))
insertables.push($rdf.st(kb.sym(sub), ns.rdfs('subClassOf'), klass, klass.doc()))
}
}
}
const doc = tracker.doc()
// const doc = tracker.doc()
const states = kb.any(tracker, ns.wf('issueClass'))
const cats = kb.each(tracker, ns.wf('issueCategory'))
var insertables = []
var deletables = []
cats.push(states)
for (const klass of cats) {
await checkOneSuperclass(klass)
checkOneSuperclass(klass)
}
const damage = insertables.length + deletables.length
if (damage) {
alert(`Internal error: s${damage} subclasses inconsistences!`)
/*
if (confirm(`Fix ${damage} inconsistent subclasses in tracker config?`)) {
await kb.updater.update(deletables, insertables)
*/
// const damage = insertables.length + deletables.length
return [deletables, insertables]
}

async function subClassFixButton (kb, tracker) {
const [deletables, insertables] = checkSubClasses(kb, tracker)
const button = widgets.button(dom, UI.icons.iconBase + 'noun_344563.svg', 'Adjust', async () => {
const [deletables, insertables] = checkSubClasses(kb, tracker)
try {
await updater.update(deletables, insertables)
alert('(Config file adjusted)')
} catch (err) {
const msg = 'Config file cant be adjusted: ' + err
alert(msg)
console.error(msg)
}
})
if (deletables.length === 0 && insertables.length === 0) {
button.setAttribute('disabled', 'yes')
}
return button
}

/** /////////////////////////// Board
*/
function renderBoard (tracker, klass) {
async function renderBoard (tracker, klass) {
const states = kb.any(tracker, ns.wf('issueClass'))
klass = klass || states // default to states
const doingStates = klass.sameTerm(states)
Expand Down Expand Up @@ -210,9 +230,11 @@ export default {
[$rdf.st(issue, ns.rdf('type'), currentState, stateStore)],
[$rdf.st(issue, ns.rdf('type'), newState, stateStore)])
} catch (err) {
UI.widgets.complain(context, 'Unable to change issue state: ' + err)
widgets.complain(context, 'Unable to change issue state: ' + err)
return
}
boardDiv.refresh() // reorganize board to match the new reality
paneDiv.refresh() // Propagate up to whole pane in fact
}

function isOpen (issue) {
Expand Down Expand Up @@ -242,12 +264,12 @@ export default {
alert(err)
return
}
UI.widgets.refreshTree(tableDiv)
widgets.refreshTree(tableDiv)
})
return refreshButton
}

function renderTable (tracker) {
async function renderTable (tracker) {
function newOptionalClause () {
const clause = new $rdf.IndexedFormula()
query.pat.optional.push(clause)
Expand Down Expand Up @@ -327,14 +349,15 @@ export default {
}

// Allow user to create new things within the folder
function renderCreationControl (refreshTarget) {
// @@ move this into common code
function renderCreationControl (refreshTarget, noun) {
const creationDiv = dom.createElement('div')
const me = UI.authn.currentUser()
const creationContext = {
// folder: subject,
div: creationDiv,
dom: dom,
noun: 'tracker',
noun: noun,
statusArea: creationDiv,
me: me,
refreshTarget: refreshTarget
Expand All @@ -344,23 +367,17 @@ export default {
UI.create.newThingUI(creationContext, context, relevantPanes) // Have to pass panes down newUI
return creationDiv
}

function renderInstances (theClass) {
async function renderInstances (theClass, noun) {
const instancesDiv = dom.createElement('div')
const context = { dom, div: instancesDiv, noun: 'tracker' }
UI.authn.registrationList(context, { public: true, private: true, type: theClass }).then(_context2 => {
instancesDiv.appendChild(renderCreationControl(instancesDiv))
/* // keep this code in case we need a form
const InstancesForm = ns.wf('TrackerInstancesForm')
const text = trackerInstancesFormText
$rdf.parse(text, kb, InstancesForm.doc().uri, 'text/turtle')
widgets.appendForm(dom, instancesDiv, {}, tracker, InstancesForm,
tracker.doc(), complainIfBad)
*/
})
const context = { dom, div: instancesDiv, noun: noun }

const _context2 = await UI.authn.registrationList(context, { public: true, private: true, type: theClass })
instancesDiv.appendChild(renderCreationControl(instancesDiv, noun))

return instancesDiv
}
function renderSettings (tracker) {

async function renderSettings (tracker) {
const settingsDiv = dom.createElement('div')
// A registration control allows the to record this tracker in their type index
const context = { dom, div: settingsDiv, noun: 'tracker' }
Expand All @@ -371,26 +388,30 @@ export default {
widgets.appendForm(dom, settingsDiv, {}, tracker, settingsForm,
tracker.doc(), complainIfBad)
})
const fixButton = await subClassFixButton(kb, tracker)
settingsDiv.append(fixButton)
return settingsDiv
}

function renderTabsTableAndBoard () {
function renderMain (ele, object) {
/* Renderthe tab system
*/
async function renderTabsTableAndBoard () {
async function renderMain (ele, object) {
ele.innerHTML = '' // Clear out "loading message"
if (object.sameTerm(boardView)) {
ele.appendChild(renderBoard(tracker))
ele.appendChild(await renderBoard(tracker))
} else if (object.sameTerm(tableView)) {
ele.appendChild(renderTable(tracker))
ele.appendChild(await renderTable(tracker))
} else if (object.sameTerm(settingsView)) {
ele.appendChild(renderSettings(tracker))
ele.appendChild(await renderSettings(tracker))
} else if (object.sameTerm(instancesView)) {
ele.appendChild(renderInstances(ns.wf('Tracker')))
ele.appendChild(await renderInstances(ns.wf('Tracker'), 'tracker'))
} else if ((kb.holds(tracker, ns.wf('issueCategory'), object)) ||
(kb.holds(tracker, ns.wf('issueClass'), object))) {
ele.appendChild(renderBoard(tracker, object))
ele.appendChild(await renderBoard(tracker, object))
} else {
throw new Error('Unexpected tab type: ' + object)
}
refreshables.push(ele.lastChild)
}
const states = kb.any(tracker, ns.wf('issueClass'))
const items = [instancesView, tableView, states]
Expand All @@ -411,14 +432,14 @@ export default {

async function renderTracker () {
function showNewIssue (issue) {
UI.widgets.refreshTree(paneDiv)
widgets.refreshTree(paneDiv)
exposeOverlay(issue, context)
b.disabled = false // https://stackoverflow.com/questions/41176582/enable-disable-a-button-in-pure-javascript
}
tracker = subject

try {
await fixSubClasses(kb, tracker)
await checkSubClasses(kb, tracker)
} catch (err) {
console.log('@@@ Error fixing subclasses in config: ' + err)
}
Expand Down Expand Up @@ -462,24 +483,24 @@ export default {
// Table of issues - when we have the main issue list
// We also need the ontology loaded
//
context.session.store.fetcher
.load([stateStore])
.then(function (_xhrs) {
const tableDiv = renderTabsTableAndBoard(tracker)
// const tableDiv = renderTable(tracker) // was
paneDiv.appendChild(tableDiv)

if (tableDiv.refresh) {
// Refresh function
} else {
console.log('No table refresh function?!')
}
paneDiv.appendChild(newTrackerButton(subject))
updater.addDownstreamChangeListener(stateStore, tableDiv.refresh) // Live update
})
.catch(function (err) {
return console.log('Cannot load state store: ' + err)
})
try {
await context.session.store.fetcher.load(stateStore)
} catch (err) {
const msg = 'Cannot load state store: ' + err
alert(msg)
return console.log(msg)
}
const tabsDiv = await renderTabsTableAndBoard(tracker)

paneDiv.appendChild(tabsDiv)

if (tabsDiv.refresh) {
// Refresh function
} else {
console.log('No table refresh function?!')
}
paneDiv.appendChild(newTrackerButton(subject, context))
updater.addDownstreamChangeListener(stateStore, paneDiv.refresh) // Live update
// end of Tracker instance
} // render tracker

Expand Down Expand Up @@ -531,7 +552,7 @@ export default {
}
paneDiv.appendChild(renderIssue(subject, context))
updater.addDownstreamChangeListener(stateStore, function () {
UI.widgets.refreshTree(paneDiv)
widgets.refreshTree(paneDiv)
}) // Live update
}
)
Expand Down
Loading