Things about the level of architecture.\n
(function() {\n createTiddlerViewer_orig_mptw_autopre = window.createTiddlerViewer;\n \n window.createTiddlerViewer = function(title,highlightText,highlightCaseSensitive) {\n \n var theBody = document.getElementById("body" + title);\n if(theBody) {\n \n var tiddler = store.tiddlers[title];\n if (typeof tiddler != "undefined" &&\n (title=="StyleSheet"\n || tiddler.getTags().indexOf("ystemConfig") != -1\n || tiddler.getTags().indexOf("ExtraStyleSheet") != -1\n // TODO: should be configurable in config instead of hard coded here...\n ))\n {\n var realText = store.getTiddlerText(title);\n var tweakedText = "{{{\sn" + realText + "\sn}}}\sn";\n tiddler.text = tweakedText;\n createTiddlerViewer_orig_mptw_autopre(title,highlightText,highlightCaseSensitive);\n tiddler.text = realText;\n }\n else {\n createTiddlerViewer_orig_mptw_autopre(title,highlightText,highlightCaseSensitive);\n }\n }\n }\n})();\n
* ParseQueryStringIntoFilters\n* MakeSourcesOptional\n* PutConfigInItsOwnFile\n* BaseCaseSourceFeeds\n* BaseCaseOutputFeeds\n\n\n''FeedQueries''\n\nSome (in fact, most) feeds are of search results; we need to construct\nURLs for them in some uniform way.\n\nSome feeds may not support all the filters we want --- figure out what\nto do in that case.\n\nWe'll also have to filter when selecting from the graph; perhaps by\nsetting up a temporary feed which has only the filtered results in.\n\nA challenge here is unifying usernames and so on across the different\nsources. That may be part of the GUZillaConfig.\n\n''Plugins and feed queriers/transformers''\n\n(see SourceFeed)\n\n'Lshift specific'\n\n* TimeZillaFeed\n\n'Generic. ish.'\n\n* [[iCalFeed]]\n* CvsZillaFeed\n* DarcsWebFeed\n* EmailFeed\n* BugzillaFeed\n
Bugzilla has an RSS feed for search results (it will give you an RSS feed of the results) and an XML format for individual bugs.\n\nWe want to produce an RSS feed of changes (new comments, status changes, etc). We'll probably have to query the database directly.\n\nOne complication is that CVSZilla puts comments in for commits, and these will turn up. We might be able to filter them out by matching on keywords.\n\n
Show a list of all the bugs, projects, components, users, etc. that are in the feed. Might be the place to allow filters too.
An RDF database.\n\nAt what abstraction level do we store data? We could load everything under their own ontologies and do lots of processing to create the view; or, we could have the [[SourceFeed]]s give results suitable for the view. \n\nThat's the difference, say between loading relevant TimeZilla database data in (grouped suitably) and doing our own formatting (in the stylesheet, say), and having the TimeZillaFeed create HTML tables for RSS-like entries.\n\nI think I prefer having a CommonOntology for setting things into a context --- a timeline, usernames, projects --- and some [[SpecialisedOntology]]s for things like tasks, bugs, and so on. The stylesheets can take care of presenting data. So only things that were originally (in the source application) entered as HTML end up as HTML in the store.\n\nThat does mean we may have to do some extra work for things like CVSZIlla, where we already have a feed.
GrandUnifiedZilla
<div class='toolbar' macro='toolbar +saveTiddler closeOthers -cancelTiddler deleteTiddler'></div>\n<div class='title' macro='view title'></div>\n<div class="editLabel">Title</div>\n<div class='editor' macro='edit title'></div>\n<div class="editLabel">Tags</div>\n<div class='editor' macro='edit tags'></div>\n<div class='editorFooter'><span\nmacro='message views.editor.tagPrompt'></span><span\nmacro='tagChooser'></span></div>\n<div class='editor' macro='edit text'></div>\n<br/>\n
What happens to feed-specific queries? Some parameters, like date range, or project, are more or less common to all the feeds. Things like showing only specific bugs, or only certain files (that are part of transactions), are particular to a certain feeds. The interface should allow for these.\n
This is where the sources are set up. I thinnk it'd be useful to have user interface for this: it can list the sources it knows about, and let people configure canned filters and so on.\n\nThe /source/ level config should simply point at the relevant places in the filesystem, load all the source feed modules (and initialise them if necessary --- providing passwords for example).\n
A tool that aggregates information from other tools --- mostly called something-zilla, hence the name --- and gives projections of that information.\n\nMy motivation for GrandUnifiedZilla was to be able to see what events led to the current status of a project; in particular, where parts of the code came from.\n\nSo, for example, I aim to be able to give a history of a block (file) of code, including the CVS transactions it was previously changed in, what bugs those were affiliated with, perhaps emails relevant to those bugs/parts of the code.\n\nHowever, for a start I will be happy to present a timeline of all the sources that the user can filter by project, person, and date range. I think that will be a large win as it is.\n\n* Repository: {{{darcs get cvs.lshift.net:/usr/local/cvsroot/archives/darcs/guzilla}}}\n* [[Architecture]]\n* [[UseCases]]\n
/*{{{*/\ndiv.header { background: #cc9;}\ndiv.headerForeground { display: block; position: relative;}\n\ndiv.headerForeground a { color: #093; }\n\n#topMenu br {display:none; }\n#topMenu { background: #360;}\n#topMenu { padding:2px; }\n#topMenu .button, #topMenu .tiddlyLink { padding-left:1em; padding-right:1em; color:white; font-size:115%;}\n#displayArea { margin: 1em 15.7em 0em 1em; }\n\n\n\n/* just in case want some QuickOpenTags in your topMenu */\n#topMenu .quickopentag { padding:0px; margin:0px; border:0px; }\n#topMenu .quickopentag .tiddlyLink { padding-right:1px; }\n#topMenu .quickopentag .button { padding-left:1px; border:0px; }\n/*}}}*/\n
[[GrandUnifiedZilla]]\n[[ToDo]]\n-----\nMainMenu\nTopMenu\nStyleSheet
This could be tricky, as the stylesheets may expect certain information.\nBest to separate the ontologies from the sources, at least, so all the ontologies can be loaded (and data will just be missing).\n
\nwindow.onClickToolbarNewHere = function(e) {\n if (!e) var e = window.event;\n clearMessage();\n if(this.parentNode.id) {\n displayTiddler(this.parentNode,"New Tiddler",2,null,null,false,false);\n tagBox = document.getElementById("editorTagsNew Tiddler"); \n tagBox.value = this.parentNode.id.substring(7);\n }\n e.cancelBubble = true;\n if (e.stopPropagation) e.stopPropagation();\n return(false);\n}\n\nconfig.views.wikified.toolbarNewHere = {text: "new here", tooltip: "Create a new tiddler with tagged as this tiddler"};\n\nwindow.createTiddlerToolbar = function (create) {\n return function(title,isEditor) {\n create(title,isEditor);\n var theToolbar = document.getElementById("toolbar" + title);\n var lingo = config.views.wikified;\n if(!isEditor) {\n createTiddlyButton(theToolbar, lingo.toolbarNewHere.text, lingo.toolbarNewHere.tooltip, onClickToolbarNewHere);\n insertSpacer(theToolbar);\n }\n }\n}(window.createTiddlerToolbar);\n
{{{\nconfig.commands.newHere = {\n text: 'new here',\n tooltip: 'Create a new tiddler tagged as this tiddler',\n handler: function(e,src,title) {\n if (!readOnly) {\n clearMessage();\n var t=document.getElementById('tiddler'+title);\n story.displayTiddler(t,config.macros.newTiddler.title,DEFAULT_EDIT_TEMPLATE);\n story.setTiddlerTag(config.macros.newTiddler.title, title, 0);\n story.focusTiddler(config.macros.newTiddler.title,"title");\n return false;\n }\n }\n};\n}}}
<div id='messageArea'></div>\n<div class='header'>\n<div class='headerForeground'>\n<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>\n<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n</div>\n<div id='topMenu' refresh='content' tiddler='TopMenu'></div>\n</div>\n<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>\n<div id='sidebar'>\n<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n<div id='tiddlerDisplay'></div>\n</div>\n
For a particular project, there are a number of sources that are relevant: CVS modules, TimeTracker tasks, Bugzilla projects and components. So a filter on 'project' is really a bundle of sometimes feed-specific query parameters. The configuration interface should allow specifying such bundles, perhaps simply as a set of feeds (with hard-wired parameters).
How does the query interface look?
There will be some query items that are common to all (or most) things: user, project, etc. There will also be things that are particular to feeds, like milestone. These /could/ affect the other feeds though: choosing a bug might filter the CVSZilla transactions shown, for example. Maybe lump all the query parameters into a dictionary and feeds can chose which they use.\n\nExcludes: we may also want to exclude things (i.e., filter *out* certain things). That could be as simple as providing 'exclude_bugs'.
//⊻ ⊽ ⋁ ▼ \n\nvar dropdownchar = (document.all?"▼":"▾"); // the fat one is the only one that works in IE\n\nvar createTagButton_orig_mptw = createTagButton;\nwindow.createTagButton = function(place,tag,excludeTiddler) {\n var sp = createTiddlyElement(place,"span",null,"quickopentag");\n createTiddlyLink(sp,tag,true,"button");\n var theTag = createTiddlyButton(sp,dropdownchar,config.views.wikified.tag.tooltip.format([tag]),onClickTag);\n theTag.setAttribute("tag",tag);\n if(excludeTiddler)\n theTag.setAttribute("tiddler",excludeTiddler);\n return(theTag);\n}\n\nconfig.macros.miniTag = {handler:function(place,macroName,params,wikifier,paramString,tiddler) {\n var tagged = store.getTaggedTiddlers(tiddler.title);\n if (tagged.length > 0) {\n var theTag = createTiddlyButton(place,dropdownchar,config.views.wikified.tag.tooltip.format([tiddler.title]),onClickTag);\n theTag.setAttribute("tag",tiddler.title);\n theTag.className = "miniTag";\n }\n}};\n\n\nconfig.macros.allTags.handler = function(place,macroName,params)\n{\n var tags = store.getTags();\n var theDateList = createTiddlyElement(place,"ul",null,null,null);\n if(tags.length == 0)\n createTiddlyElement(theDateList,"li",null,"listTitle",this.noTags);\n for (t=0; t<tags.length; t++)\n {\n var theListItem =createTiddlyElement(theDateList,"li",null,null,null);\n var theLink = createTiddlyLink(theListItem,tags[t][0],true);\n var theCount = " (" + tags[t][1] + ")";\n theLink.appendChild(document.createTextNode(theCount));\n\n var theDropDownBtn = createTiddlyButton(theListItem," "+dropdownchar,this.tooltip.format([tags[t][0]]),onClickTag);\n theDropDownBtn.setAttribute("tag",tags[t][0]);\n }\n}\n\n\nsetStylesheet(\n ".quickopentag { margin-right:1.2em; border:1px solid #eee; padding:2px; padding-right:0px; padding-left:1px; }\sn"+\n ".quickopentag .tiddlyLink { padding:2px; padding-left:3px; }\sn"+\n ".quickopentag a.button { padding:1px; padding-left:2px; padding-right:2px;}\sn"+\n "a.miniTag {font-size:150%;}\sn"+\n "",\n"QuickOpenTagStyles");\n
// Make the order of tiddlers when saved a configurable option\n\nconfig.options.chkSaveLexicalOrder = false;\nloadOptionsCookie();\n\nfunction allTiddlersAsHtml()\n{\n var savedTiddlers = [];\n var orderBy = (config.options.chkSaveLexicalOrder) ? "title" : "modified";\n var tiddlers = store.getTiddlers(orderBy);\n for (var t = 0; t < tiddlers.length; t++)\n savedTiddlers.push(tiddlers[t].saveToDiv());\n return savedTiddlers.join("\sn");\n}\n
If I was cool I would have called it Mothra.
GrandUnifiedZilla!
Little snippets of ideas, to be filed as something else eventually. Or not.
Sources of data. These won't all be already available as RSS feeds, so sometimes we'll have to fake it (or hack on the application to get a usable RSS feed).\n\nWhat is the type of a source? Something like:\n\n{{{store x maybe username x maybe project x maybe start x maybe end -> ()}}}\n\ni.e., you supply all the query things and it figures out how to load all the data into the DataStore.
/*{{{*/\n\n[[HeaderStyles]]\n[[TagglyTaggingStyles]]\n\nbody {\n max-width: 960px;\n}\n\n.editor input, .editor textarea {\n opacity: 0.7;\n}\n\ndiv#mainmenu hr {margin:0px;padding:0px;padding-top:10px;\n border-style:none;\n border-width:1px;\n border-color:#ccc;\n border-bottom-style:solid;\n}\n\n.button {border: 1px solid transparent;}\n\n.viewer pre { font-size:110%; }\n\n#displayArea {\n margin-right: 15.5em;\n margin-left: 13em;\n}\n\n// this works great in firefox but breaks something with ie. help??\n// .toolbar { float:right; }\n\n\n.viewer h1,\n.viewer h2,\n.viewer h3,\n.viewer h4,\n.viewer h5 { font-family: 'Trebuchet MS' Arial sans-serif; background:#f8f8f8; }\n\n.viewer h1 { font-size:1.2em; }\n.viewer h2 { font-size:1.1em; }\n.viewer h3 { font-size:1.0em; }\n.viewer h4 { font-size:0.9em; }\n.viewer h5 { font-size:0.8em; }\n\nbody {\n background:#eee;\n}\n\ndiv.tiddler {\n background:white;\n border-top:solid #ccc 2px;\n border-left:solid #ccc 2px;\n border-bottom:solid #aaa 2px;\n border-right:solid #aaa 2px;\n margin-bottom:5px;\n padding-bottom:10px;\n}\n\ndiv.title {\n font-family:'Trebuchet MS' Arial sans-serif;\n font-size:150%;\n}\n\ndiv.editor input,\ndiv.editor textarea {\n background:#ffe;\n border:solid #aa9 2px;\n margin:4px;\n}\n\n@media print {\n div.tiddler {border:none white 0px; border-top:solid #bbb 1px;}\n div.tagged {border:none white 0px;}\n #titleLine { display:none; }\n #displayArea { margin-right: 0px; margin-left: 0px; }\n .toolbar { display:none; }\n}\n/*}}}*/\n
// this function lifted mostly from Josh's incomingTags macro at serversidewiki.com\n// makes a wiki text list of all tagged tiddlers\nfunction getTaggedTiddlersText(title, sortby) {\n if (!sortby) {\n // sortby="modified";\n sortby="title"; \n }\n var tags = store.getTaggedTiddlers(title,sortby);\n var str=""; \n for (i=0; i<tags.length; i++) {\n str+="* [[" + tags[i].title + "]]\sn";\n // TODO. make a comma separated version too\n // have an option to select between them\n }\n return str;\n}\n\n// use this to (re)build the tagged list for a tiddler\nfunction refreshTaggedList(title) {\n \n var theViewer = document.getElementById("viewer"+title);\n \n if (theViewer) {\n \n var theTaggedList = document.getElementById("tagged"+title);\n if (theTaggedList) {\n theViewer.removeChild(theTaggedList);\n }\n \n var taggedText = getTaggedTiddlersText(title,"title");\n \n if (taggedText != "") {\n var newTaggedList = createTiddlyElement(theViewer,"div","tagged" + title,"tagged",null); \n wikify(getTaggedTiddlersText(title),newTaggedList); \n }\n }\n}\n\n// I want to refresh the tagged list in other visible tiddlers\n// this is to refresh if we remove a tiddler\nwindow.deleteTiddler = (function(del) {\n \n return function(title) {\n var oldtags = [];\n var tiddler = store.tiddlers[title];\n if (tiddler) {\n var oldtags = tiddler.tags;\n }\n \n del(title);\n \n for (i=0; i<oldtags.length; i++) {\n refreshTaggedList(oldtags[i]);\n }\n };\n })(window.deleteTiddler);\n\n// this is if we edit a tiddler\n// refresh tags on screen\nwindow.saveTiddler = (function(save) {\n return function(title) {\n \n var newTitle = document.getElementById("editorTitle"+title).value;\n \n var oldtags = [];\n var tiddler = store.tiddlers[title];\n if (tiddler) {\n var oldtags = tiddler.tags;\n }\n \n save(title);\n \n var newtags = store.tiddlers[newTitle].tags;\n \n for (i=0; i<newtags.length; i++) {\n refreshTaggedList(newtags[i]);\n }\n \n // will do lots twice. should do a unique on oldtags and newtags\n // probably its fast enough that we don't care\n \n for (i=0; i<oldtags.length; i++) {\n refreshTaggedList(oldtags[i]);\n }\n };\n \n })(window.saveTiddler);\n\n//==========================================================\n\n\nwindow.createTiddlerViewer = (function(create) {\n return function(title,highlightText,highlightCaseSensitive) {\n create(title,highlightText,highlightCaseSensitive);\n refreshTaggedList(title);\n };\n })(window.createTiddlerViewer);\n\n//==========================================================\n// only change in this is to put the footer above the title... \n// I know that's a bit strange but it's the easiest way to move the tag buttons\n\n\nwindow.createTiddlerSkeleton = (function(create) {\n return function(place,before,title)\n {\n var theTiddler = create(place,before,title);\n theFooter = document.getElementById("footer"+title);\n theTitle = document.getElementById("title"+title);\n // want to put the footer up above the title\n theTiddler.childNodes[0].insertBefore(theFooter,theTitle);\n return(theTiddler);\n };\n })(window.createTiddlerSkeleton);\n\n//==========================================================\n// I want a TiddlyLink in place of a TagButton\n\nwindow.createTagButton = function(place,tag,excludeTiddler) {\n return createTiddlyLink(place,tag,tag);\n}\n\n//==========================================================\n// this is to make the Tags tab work the same. TiddlyLink instead of Tag button\n// TODO: currently we lose the Tag count display\n \n config.macros.allTags.handler = function(place,macroName,params) {\n var tags = store.getTags();\n if(tags.length == 0) {\n createTiddlyElement(place,"div",null,null,this.noTags);\n }\n for (t=0; t<tags.length; t++) {\n var theTag = createTiddlyLink(place,tags[t][0],tags[t][0] + " (" + tags[t][1] + ")");\n theTag.setAttribute("tag",tags[t][0]);\n place.appendChild(document.createElement("br"));\n }\n }\n \n config.views.wikified.tag.labelNoTags = "";\nconfig.views.wikified.tag.labelTags = "";\n\nsetStylesheet(\n "div.tagged {background:#f8f8f8;margin-top:0.5em;border: solid #f0f0f0 3px;}\sn"+\n "div.tagged ul {padding-top:0px;margin-top:4px;margin-bottom:8px;list-style-type:square;}\sn"+\n "div.footer a.tiddlyLink { padding-top:0px;margin-right:1.2em;}\sn"+\n "div.footer {margin-top:0px;padding-top:0px;}\sn"+\n "",'tagglyTaggingStyles');\n\n\n
.tagglyTagged li.listTitle { display:none;}\n.tagglyTagged li { display: inline; font-size:90%; }\n.tagglyTagged ul { margin:0px; padding:0px; }\n.tagglyTagging li.listTitle { display:none;}\n.editLabel { font-size:90%; padding-top:0.5em; }\n
Either do queries directly to the database, or send them to TimeZilla and scrape for the tables. TimeZilla doesn't really do reports interesting for us, so perhaps the former; e.g., summarised by week, summarised by day.\n\nIs there some kind of granularity, or summary level control? We can load daily summaries and do our own {week, month} summation as post-processing, or get the database to do that for us.\n\nLee uses hibernate to model and query the database. We don't have to be so sophisticated; it would probably be ok to just query the DB and load directly into the DataStore.
[[Architecture]] | [[UseCases]] | [[Sketches]]
Fantasy (for now) scenarios of what I'd like people to be able to do with GrandUnifiedZilla.\n
Users have (slightly) different names in different systems, so we'll have to be able to know for each what to query on. We need a way of translating: either automatically, or by lookup.\n\nPerhaps by having configuration that makes equivalencies but useful for querying feeds and for querying the DataStore.
Matters of user interface.
A wiki captures the current knowledge (as far as it is maintained); however, often one wants to know, for instance, how a decision was made.\n\nFor example, say the code has changed and someone disagrees with the change. You need to find out why the change was made. CVS(Zilla) records what the change encompassed, bugzilla may record that the change fixed a bug, and a wiki may have the specification that the change agrees with. These are only tenuously linked, and nowhere is found the chain of events leading to the change.\n\nIn this scenario, a user should be able to go to GrandUnifiedZilla, find the CVSZilla transaction, and trace the relevant files, bugs, changes to wiki pages, and messages (email, blog posts).
<div class='toolbar' macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump newHere'></div>\n<div class="tagglyTagged" macro="tags"></div>\n<div><span class='title' macro='view title'></span><span class="miniTag" macro="miniTag"></span></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class="tagglyTagging" macro="tagging"></div>
Weekly reports are kind of like checkpoints, summarising what was expected for the last week, and what actually happened, and what should happen in the next week. It would be informative, and a great help to preparing weekly reports, to be able to view a week's activity sandwiched between weekly reports.\n