Archiv für März 2011

ALM mit Redmine, Teil 2

Im ersten Teil hatte ich ja bereits angekündigt, dass ich über unsere Erfahrungen mit Redmine weiter berichten werde. Leider hat sich das Ganze anders entwickelt als gedacht. Da bei uns vornehmlich Outlook zum Einsatz kommt und wir auch alle unsere Kundendaten im Outlook haben, nutzen wir jetzt doch eine Kommerzielle Erweiterung für Outlook um unsere Support-Anfragen zu bearbeiten. Aber nichts des do trotz arbeite ich jetzt erst mal alleine mit Redmine.

Da ich mehrere kleine und große Projekte habe, die ich in Eigenregie plane und Entwickle ist eine gute Aufgabenplanung unerlässlich. Mit Redmine habe ich jetzt endlich ein vernünftiges Werkzeug dafür gefunden. Ich habe mehrere Projekte und Unterprojekte in denen vor allem die drei Tracker “Bug”,  “Feature” und “Anforderung” zum Einsatz kommen. Für Bugs war das ganze ja sowieso gedacht, jetzt kommt der Bugtracker halt zum Einsatz wenn ich selber Fehler finde oder der Kunde mir direkt welche schickt. Im Tracker “Feature” landen Ideen für Erweiterungen unserer Produkte.

Besonders wichtig ist für mich in letzter Zeit der Tracker “Anforderung” geworden. Da es sich hier um konkrete Aufgaben handelt, welche für den Kunden abgearbeitet werden müssen, ist das der Tracker mit den meisten Tickets. Außerdem nutze ich den Tracker dafür, meine Aufwände zu Planen. Ich zerlege die Aufgaben so, dass ich bei Maximal ein bis zwei Tagen, am besten jedoch bei ein bis zwei Stunden rauskomme. Somit kann ich bei einem Angebot ziemlich zuverlässig sagen wie viel Manntage bezahlt werden müssen.

Damit die Planung auch Sinnvoll und Realistisch ist, muss natürlich der tatsächliche Aufwand mit erfasst werden. Erst dadurch ist es möglich die Abschätzungen zu überprüfen und bei neuen Aufgaben genauere Zahlen zu liefern. Damit man nicht ständig auf die Uhr schauen muss wenn man an einer Aufgabe arbeitet, gibt es zum Glück das TimeTracker Plugin. Es zeigt in der rechten oberen Ecke einen Button “Start #xxx” mit dem die Zeiterfassung für die aktuelle Aufgabe begonnen werden kann. Wenn der Timer läuft wird an dieser Stelle immer die aktuell benötigte Zeit angezeigt. Und da es wahrscheinlich vielen so geht wie mir, die beim Arbeiten durch Telefonate oder Sonstiges abgehalten werden, gibt es einen Pause-Button, welcher die Zeitmessung unterbricht. Drück man schließlich auf den Stopp-Button öffnet sich automatisch die Aufwands-Erfassungsmaske, in der die benötigte Zeit, in Stunden umgerechnet, bereits eingetragen ist. Hier kann man nun noch ein Kommentar mit einer Beschreibung der Tätigkeit eingeben und das Ganze als Tätigkeit für die Aufgabe speichern.

Da bei mir der Berg an Papier mit Feature-Wünschen und Anpassungen von unseren Kunden immer weiter gewachsen ist und ich da nicht mehr wirklich durchgesehen habe, wird so etwas jetzt immer eingescannt. Die PDF Datei hänge ich dann an die konkrete Aufgabe oder den Fehler als Anlage mit dran. Somit entfällt das lange Gesuche nach irgendwelchen Blättern mir Designvorgaben und Co. Das gleiche gilt natürlich auch für Dokumente oder Screenshots die ich per Mail erhalten habe. Sollte solch eine Datei mehrere Aufgaben betreffen, gibt es in Redmine die Möglichkeit, Dokumente zu einem Projekt zu speichern. Diesen Dokumenten gibt man einen Namen und eine kurze Beschreibung. Per document#xxx (xxx ist die ID des Dokuments) kann man dann schließlich in der Beschreibung einer Aufgabe oder einem Kommentar auf das Dokument verlinken. Hierbei wird der Ausdruck mit dem Dokumentnamen ersetzt. Es gibt übrigens eine ganze Reihe solcher Ausdrücke , um zwischen Dokumenten, Wiki-Einträgen und anderen Aufgaben zu verlinken. Eine Übersicht dafür liefert die Wiki-Seite von Redmine.

Advertisements

Hinterlasse einen Kommentar

jQuery Tablesorter Pager: Jump to Page

This is my first blog in english, so sorry for any spelling errors.

In one of our projects, we use the great jQuery library. A very cool plugin for jQuery is the tablesorter and the extsion to this, the pager. The only disadvantage of the pager plugin is the missing function “Jump To Page”. You can only display the current page and the page count as one string. So i have modified the code of the pager plugin a little, to add this function.

It is a very simple extension, only two existing functions need to be updated. To identify the input-field for the current page and the div for the pagecount, i added two new properties to the settings: cssPageCurrent and cssPageCount. The first function to update is the constructur. Here i connect to the change-event of the input-field and call the moveToPage function. The second function is named updatePageDisplay. It is responsible to update the number in the currentpage-inputfield if you navigate with the next/prev buttons.

Here are the updated functions:

function updatePageDisplay(c, table) {
    var txt = (c.page + 1) + c.seperator + c.totalPages;
    var pd = $(c.cssPageDisplay, c.container)
    if (pd.is("input"))
        pd.val(txt);
    else
        pd.text(txt);

    var pcur = $(c.cssPageCurrent, c.container)
    if (pcur.is("input"))
        pcur.val(c.page + 1);
    else
        pcur.text(c.page + 1);

    var pcount = $(c.cssPageCount, c.container)
    if (pcount.is("input"))
        pccount.val(c.totalPages);
    else
        pcount.text(c.totalPages);

    $(table).trigger("tableSorterPagerUpdatePageDisplay");
}

this.defaults = {
    size: 10,
    offset: 0,
    page: 0,
    totalRows: 0,
    totalPages: 0,
    container: null,
    cssNext: '.next',
    cssPrev: '.prev',
    cssFirst: '.first',
    cssLast: '.last',
    cssPageDisplay: '.pagedisplay',
    cssPageSize: '.pagesize',
    cssPageCount: '.pagecount',
    cssPageCurrent: '.pagecurrent',
    seperator: "/",
    positionFixed: true,
    appender: this.appender
};

this.construct = function (settings) {

    return this.each(function () {

        ...

        $(config.cssPageCurrent, pager).change(function () {
            var c = table.config;
            var p = $(this).val();

            if (p != c.page + 1) {
                p = parseInt(p) - 1;
                if (p < 0 || isNaN(p)) p = 0;
                else if (p > c.totalPages - 1) p = c.totalPages - 1;

                c.page = p;
                moveToPage(table);
            }

            return false;
        });
    });
};

Here you can download the changed scriptfile: jquery.tablesorter.pager.js

And here is how i used it:

<html>
<head>
    <script type="text/javascript">
        $(document).ready(function () {
            ...
            $(".tblSortable").tablesorter();
            $(".tblSortable").tablesorterPager({ container: $("#pager"), positionFixed: false, size: 30 });
            ...
        });
    </script>
</head>
<body>
    ...
    <div id="pager" align="center">
        <input type="text" name="pagecurrent" class="pagecurrent">
        <span> / </span>
        <span class="pagecount">1</span>
    </div>
    ...   
    <table class="tblSortable">
        ...
    </table>      
</body>
</html>

,

2 Kommentare