mirror of
https://github.com/fazo96/pbs.git
synced 2025-01-26 14:24:20 +01:00
major new feature: Resources
This commit is contained in:
parent
0ad54bee53
commit
d1414f2532
@ -1,14 +1,17 @@
|
||||
class PBS
|
||||
constructor: (obj, @verbose, @errListener) ->
|
||||
@days = []
|
||||
@resources = []
|
||||
@criticalPaths = []
|
||||
@verbose = yes
|
||||
if obj.push # is a list
|
||||
@list = obj
|
||||
else if obj.activities
|
||||
@list = obj.activities
|
||||
if obj.resources?.push? then @resources = obj.resources
|
||||
else
|
||||
@list = []
|
||||
@err 'data is not an array nor a object with "activities" array'
|
||||
@err 'data is not an array nor a object with "activities" array'
|
||||
|
||||
log: (x...) ->
|
||||
if @verbose
|
||||
@ -21,6 +24,24 @@ class PBS
|
||||
else console.log "[ !Pert! ]", x...
|
||||
if @errListener?.call? then @errListener x
|
||||
|
||||
compileResources: =>
|
||||
@log 'compiling resources...'
|
||||
if not @resources? then return
|
||||
@resources.forEach (x) =>
|
||||
@log 'processing resource', x
|
||||
if x.assignedTo?.push? then x.assignedTo.forEach (i) =>
|
||||
a = @toActivity i
|
||||
a.assigned ?= []
|
||||
a.assigned.push x.name or x.id
|
||||
@list.forEach (x) =>
|
||||
item = @toActivity x
|
||||
if item.assigned?.push? then item.assigned.forEach (i) =>
|
||||
res = @toResource i
|
||||
if res
|
||||
@log 'found', res, 'assigned to', item
|
||||
res.assignedTo ?= []
|
||||
res.assignedTo.push i
|
||||
|
||||
# Returns the highest number in an array of numbers
|
||||
maxa: (l) -> return Math.max.apply null, l
|
||||
|
||||
@ -32,6 +53,14 @@ class PBS
|
||||
if x.id is id then item = x
|
||||
return item
|
||||
|
||||
# Find the activity with given id
|
||||
toResource: (id) =>
|
||||
unless @resources?.push? then return
|
||||
item = {}
|
||||
for i,x of @resources
|
||||
if x.id is id or x.name is id then item = x
|
||||
return item
|
||||
|
||||
# Compute the item's end day
|
||||
calculateEndDay: (item) =>
|
||||
if !item.startDay?
|
||||
@ -83,11 +112,14 @@ class PBS
|
||||
@log "calculating path from",path
|
||||
lastID = path[path.length - 1]
|
||||
last = @toActivity lastID
|
||||
if last.dependant? and last.dependant.length > 0
|
||||
if last.permittedDelay > 0
|
||||
@log "dead end at", lastID, "because its delay is", last.permittedDelay
|
||||
else if last.dependant? and last.dependant.length > 0
|
||||
last.dependant.forEach (x) =>
|
||||
ii = @toActivity x
|
||||
delay = ii.permittedDelay or 0
|
||||
if delay is 0
|
||||
@log 'following path from', last.id, 'to', ii.id, 'because', ii, 'has', ii.permittedDelay, 'days of free delay'
|
||||
@calculateCriticalPaths path.concat x
|
||||
else
|
||||
@log "dead end at", lastID, "-->", x, "because delay is", delay
|
||||
@ -124,13 +156,16 @@ class PBS
|
||||
for x,i in @list
|
||||
if !x.depends? or x.depends.length is 0
|
||||
@calculateCriticalPaths [x.id]
|
||||
results = activities: @list, days: @days, criticalPaths: @criticalPaths
|
||||
@compileResources()
|
||||
results =
|
||||
activities: @list
|
||||
days: @days
|
||||
criticalPaths: @criticalPaths
|
||||
resources: @resources || []
|
||||
@log 'Done', results
|
||||
if options?.json
|
||||
if cb? then cb(JSON.stringify results)
|
||||
JSON.stringify results
|
||||
else
|
||||
if cb? then cb(results)
|
||||
results
|
||||
|
||||
# export module to node environment
|
||||
if module?.exports? then module.exports = PBS
|
||||
|
@ -33,13 +33,18 @@ pertApp.config ($stateProvider,$urlRouterProvider,$locationProvider) ->
|
||||
templateUrl: 'table.html'
|
||||
controller: pertController
|
||||
|
||||
$stateProvider.state 'resources',
|
||||
url: '/resources'
|
||||
templateUrl: 'resources.html'
|
||||
controller: pertController
|
||||
|
||||
# "Main" Controller
|
||||
pertController = ($scope) ->
|
||||
$scope.toLocalStorage = (data,options) ->
|
||||
options ?= {}
|
||||
data ?= []
|
||||
if !data.push?
|
||||
return swal 'Error', 'data is not a list', 'error'
|
||||
if !data.push? and !data.activities?.push?
|
||||
return swal 'Error', 'data is not a valid PBSlib object', 'error'
|
||||
try
|
||||
sdata = JSON.stringify data
|
||||
console.log "Saving: "+sdata
|
||||
@ -54,22 +59,17 @@ pertController = ($scope) ->
|
||||
$scope.fromLocalStorage = (options) ->
|
||||
options = options || {}
|
||||
data = localStorage.getItem options.name || 'ganttpert'
|
||||
if data is null then data = "[]"
|
||||
if data is null then data = '{"activities":[], "resources":[]}'
|
||||
try
|
||||
jdata = JSON.parse data
|
||||
if jdata is null then jdata = []
|
||||
if jdata is null then jdata = activities: [], resources: []
|
||||
catch e
|
||||
unless options.silent
|
||||
swal 'JSON Error', e, 'error'
|
||||
if options.raw
|
||||
#console.log 'Loading: []'
|
||||
return []
|
||||
else
|
||||
#console.log 'Loading: {list: [], days: []}'
|
||||
return list: [], days: []
|
||||
return activities: [], resources: []
|
||||
if options.raw
|
||||
#console.log 'Loading: '+jdata
|
||||
return jdata
|
||||
else
|
||||
#console.log 'Loading: '+$scope.pbs
|
||||
return $scope.pbs ?= new PBS(jdata).calculate()
|
||||
return $scope.pbs = new PBS(jdata).calculate()
|
||||
|
@ -1,12 +1,18 @@
|
||||
pertApp.controller 'tableController', ($scope) ->
|
||||
tableController = ($scope,getList) ->
|
||||
$scope.list = []
|
||||
$scope.refreshTable = ->
|
||||
ls = $scope.fromLocalStorage()
|
||||
if ls?
|
||||
$scope.list = ls.activities
|
||||
data = $scope.fromLocalStorage()
|
||||
if data?
|
||||
$scope.list = getList data
|
||||
$scope.$on 'dataChanged', $scope.refreshTable
|
||||
$scope.refreshTable()
|
||||
|
||||
|
||||
pertApp.controller 'tableController', ($scope) ->
|
||||
tableController $scope, (data) -> data.activities or []
|
||||
pertApp.controller 'resourceTableController', ($scope) ->
|
||||
tableController $scope, (data) -> data.resources or []
|
||||
|
||||
pertApp.controller 'pertDiagController', ($scope) ->
|
||||
$scope.buildGraph = (data) ->
|
||||
if !data? then return
|
||||
@ -31,7 +37,6 @@ pertApp.controller 'pertDiagController', ($scope) ->
|
||||
style: 'arrow'
|
||||
network = new vis.Network (document.getElementById 'pertDiagram'), { nodes: nodes, edges: connections }, options
|
||||
$scope.rebuild = ->
|
||||
console.log 'rebuild'
|
||||
$scope.buildGraph $scope.fromLocalStorage()
|
||||
$scope.$on 'dataChanged', $scope.rebuild
|
||||
$scope.rebuild()
|
||||
@ -52,7 +57,7 @@ pertApp.controller 'ganttDiagController', ($scope) ->
|
||||
|
||||
pertApp.controller 'rawEditorController', ($scope) ->
|
||||
$scope.reset = ->
|
||||
$scope.toLocalStorage []
|
||||
$scope.toLocalStorage { activities: [], resources: [] }
|
||||
$scope.saveData = ->
|
||||
try
|
||||
data = JSON.parse $scope.taData
|
||||
@ -61,46 +66,55 @@ pertApp.controller 'rawEditorController', ($scope) ->
|
||||
$scope.toLocalStorage data
|
||||
$scope.reloadData = ->
|
||||
$scope.taData = JSON.stringify $scope.fromLocalStorage silent: yes, raw: yes
|
||||
$scope.$on 'dataChanged', ->
|
||||
$scope.reloadData()
|
||||
#$('#ta').val JSON.stringify $scope.fromLocalStorage silent: yes, raw: yes
|
||||
$scope.$on 'dataChanged', $scope.reloadData
|
||||
$scope.reloadData()
|
||||
|
||||
pertApp.controller 'editorController', ($scope) ->
|
||||
$scope.list = []
|
||||
$scope.clone = (id) ->
|
||||
for i,j of $scope.fromLocalStorage({raw: yes, silent: yes})
|
||||
$scope.activities = []
|
||||
$scope.resources = []
|
||||
$scope.actID = ''; $scope.actDur = ''; $scope.actDeps = ''
|
||||
$scope.resID = ''; $scope.resName = ''; $scope.resAss = ''
|
||||
$scope.clone = (isResource, id) ->
|
||||
data = $scope.fromLocalStorage({raw: yes, silent: yes})
|
||||
l = if isResource then data.resources else data.activities
|
||||
for i,j of $scope.fromLocalStorage({raw: yes, silent: yes}).activities
|
||||
if j.id is id
|
||||
$scope.addNew j.id, j.duration, j.depends
|
||||
swal 'Ok', id+' has been cloned', 'success'
|
||||
return
|
||||
swal 'Ops', 'could not find '+id, 'warning'
|
||||
|
||||
$scope.delete = (index,id) ->
|
||||
$scope.delete = (isResource, index,id) ->
|
||||
newdata = $scope.fromLocalStorage raw: yes
|
||||
iter = if isResource then newdata.resources else newdata.activities
|
||||
l = []
|
||||
if id? then for i,j of newdata
|
||||
if id isnt j.id
|
||||
if id? then for i,j of iter
|
||||
if id isnt j.id and id isnt j.name
|
||||
l.push j
|
||||
else for i,j of newdata
|
||||
else for i,j of iter
|
||||
if parseInt(i) isnt index
|
||||
l.push j
|
||||
diff = newdata.length - l.length
|
||||
$scope.toLocalStorage l, silent: yes
|
||||
diff = iter.length - l.length
|
||||
if isResource
|
||||
newdata.resources = l
|
||||
else newdata.activities = l
|
||||
$scope.toLocalStorage newdata, silent: yes
|
||||
if diff isnt 1
|
||||
swal 'Done', diff+' item(s) deleted', 'warning'
|
||||
|
||||
$scope.addNew = (id, dur, deps) ->
|
||||
dur ?= $('#new-duration').val().trim()
|
||||
id ?= $('#new-id').val().trim()
|
||||
$scope.addNew = (isResource, id, dur, deps) ->
|
||||
dur ?= if isResource then $scope.resName else $scope.actDur
|
||||
id ?= if isResource then $scope.resID else $scope.actID
|
||||
if !deps?
|
||||
deps = $('#new-deps').val().split(' ')
|
||||
deps = if isResource then $scope.resAss else $scope.actDeps
|
||||
deps = deps.split ' '
|
||||
if deps.length is 1 and deps[0] is ''
|
||||
deps = []
|
||||
try
|
||||
dur = parseInt dur
|
||||
catch e
|
||||
return swal 'Error', 'duration must be an integer', 'error'
|
||||
if !isResource
|
||||
try
|
||||
dur = parseInt dur
|
||||
catch e
|
||||
return swal 'Error', 'duration must be an integer', 'error'
|
||||
try
|
||||
unless isNaN id
|
||||
id = parseInt id
|
||||
@ -110,13 +124,22 @@ pertApp.controller 'editorController', ($scope) ->
|
||||
deps[i] = parseInt dep
|
||||
catch e
|
||||
newdata = $scope.fromLocalStorage silent: yes, raw: yes
|
||||
if !newdata? or newdata is null or !newdata.push?
|
||||
newdata = []
|
||||
newdata.push { id: id, duration: dur, depends: deps }
|
||||
$scope.toLocalStorage newdata, silent: yes
|
||||
if isResource
|
||||
if newdata?.resources?.push?
|
||||
console.log newdata.resources
|
||||
newdata.resources.push { id: id, name: dur, assignedTo: deps }
|
||||
$scope.toLocalStorage newdata, silent: yes
|
||||
else console.log "wtf cant add, data broken"
|
||||
else
|
||||
if newdata?.activities?.push?
|
||||
newdata.activities.push { id: id, duration: dur, depends: deps }
|
||||
$scope.toLocalStorage newdata, silent: yes
|
||||
else console.log "wtf cant add, data broken"
|
||||
|
||||
|
||||
$scope.refreshEditor = ->
|
||||
data = $scope.fromLocalStorage { silent: yes, raw: yes }
|
||||
$scope.list = data || []
|
||||
$scope.activities = data.activities || []
|
||||
$scope.resources = data.resources || []
|
||||
$scope.$on 'dataChanged', $scope.refreshEditor
|
||||
$scope.refreshEditor()
|
||||
|
@ -4,7 +4,7 @@
|
||||
<p class="lead">Dependencies must be a list of IDs separated by space<br>
|
||||
the program does not check cyclic or invalid dependencies for you</p>
|
||||
</div>
|
||||
<!-- new item -->
|
||||
<!-- new activity -->
|
||||
<div class="panel panel-default new-activity-panel">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-plus"></i> New Activity
|
||||
@ -12,21 +12,21 @@
|
||||
<div class="panel-body">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">ID</span>
|
||||
<input class="form-control" placeholder="New Activity" ng-model="newid" id="new-id">
|
||||
<input class="form-control" placeholder="New Activity" ng-model="actID" id="new-id">
|
||||
</div>
|
||||
<div class="input-group duration">
|
||||
<span class="input-group-addon">Duration</span>
|
||||
<input class="form-control" id="new-duration" placeholder="(days)">
|
||||
<input class="form-control" ng-model="actDur" placeholder="(days)">
|
||||
</div>
|
||||
<div class="input-group dependencies">
|
||||
<span class="input-group-addon">Dependencies</span>
|
||||
<input class="form-control" placeholder="id1 id2 id3" id="new-deps">
|
||||
<input class="form-control" placeholder="id1 id2 id3" ng-model="actDeps">
|
||||
</div>
|
||||
<button ng-click="addNew()" class="btn btn-primary">
|
||||
<button ng-click="addNew(false)" class="btn btn-primary">
|
||||
<i class="fa fa-plus"></i> Add</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- item list -->
|
||||
<!-- activity list -->
|
||||
<table id="tab" class="table">
|
||||
<tr>
|
||||
<td><b>#</b></td>
|
||||
@ -35,11 +35,11 @@
|
||||
<td><b>Dependencies</b></td>
|
||||
<td><b>Commands</b></td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in list">
|
||||
<tr ng-repeat="item in activities">
|
||||
<td>{{$index + 1}}</td>
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.duration}}</td>
|
||||
<td>{{item.depends || []}}</td>
|
||||
<td>{{item.depends.join(', ') || "None"}}</td>
|
||||
<td>
|
||||
<button class="btn btn-info" ng-click="clone(item.id)">
|
||||
<i class="fa fa-copy"></i>
|
||||
@ -50,4 +50,51 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<!-- new resource -->
|
||||
<div class="panel panel-default new-activity-panel">
|
||||
<div class="panel-heading">
|
||||
<i class="fa fa-plus"></i> New Resource
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">ID</span>
|
||||
<input class="form-control" placeholder="New Resource" ng-model="resID">
|
||||
</div>
|
||||
<div class="input-group duration">
|
||||
<span class="input-group-addon">Name</span>
|
||||
<input class="form-control" ng-model="resName" placeholder="new resource name">
|
||||
</div>
|
||||
<div class="input-group dependencies">
|
||||
<span class="input-group-addon">Assigned To</span>
|
||||
<input class="form-control" placeholder="id1 id2 id3" ng-model="resAss">
|
||||
</div>
|
||||
<button ng-click="addNew(true)" class="btn btn-primary">
|
||||
<i class="fa fa-plus"></i> Add</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- resource list -->
|
||||
<table id="tab" class="table">
|
||||
<tr>
|
||||
<td><b>#</b></td>
|
||||
<td><b>ID</b></td>
|
||||
<td><b>Name</b></td>
|
||||
<td><b>Assignations</b></td>
|
||||
<td><b>Commands</b></td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in resources">
|
||||
<td>{{$index + 1}}</td>
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.name}}</td>
|
||||
<td>{{item.assignedTo || []}}</td>
|
||||
<td>
|
||||
<button class="btn btn-info" ng-click="clone(true,item.id)">
|
||||
<i class="fa fa-copy"></i>
|
||||
</button>
|
||||
<button class="btn btn-danger" ng-click="delete(true,$index)">
|
||||
<i class="fa fa-remove"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -37,7 +37,8 @@
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a ui-sref="edit">Edit</a></li>
|
||||
<li><a ui-sref="rawedit">RawEdit</a></li>
|
||||
<li><a ui-sref="table">Table</a></li>
|
||||
<li><a ui-sref="table">Activities</a></li>
|
||||
<li><a ui-sref="resources">Resources</a></li>
|
||||
<li><a ui-sref="pert">Pert</a></li>
|
||||
<li><a ui-sref="gantt">Gantt</a></li>
|
||||
<li class="github"><a href="http://github.com/fazo96/pbs">GitHub</a></li>
|
||||
|
14
src/resources.html
Normal file
14
src/resources.html
Normal file
@ -0,0 +1,14 @@
|
||||
<table id="tab" class="table" ng-controller="resourceTableController">
|
||||
<tr>
|
||||
<td><b>#</b></td>
|
||||
<td><b>ID</b></td>
|
||||
<td><b>Name</b></td>
|
||||
<td><b>Assigned To</b></td>
|
||||
</tr>
|
||||
<tr ng-repeat="item in list">
|
||||
<td>{{$index + 1}}</td>
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.name}}</td>
|
||||
<td>{{item.assignedTo.join(', ') || "None"}}</td>
|
||||
</tr>
|
||||
</table>
|
@ -6,6 +6,7 @@
|
||||
<td><b>Start Day</b></td>
|
||||
<td><b>Depends On</b></td>
|
||||
<td><b>Dependant</b></td>
|
||||
<td><b>Resources</b></td>
|
||||
<td><b>End Day</b></td>
|
||||
<td><b>Free Delay</b></td>
|
||||
<td><b>Chained Delay</b></td>
|
||||
@ -15,8 +16,9 @@
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.duration}}</td>
|
||||
<td>{{item.startDay}}</td>
|
||||
<td>{{item.depends || "N/A"}}</td>
|
||||
<td>{{item.dependant || "N/A"}}</td>
|
||||
<td>{{item.depends.join(', ') || "None"}}</td>
|
||||
<td>{{item.dependant.join(', ') || "None"}}</td>
|
||||
<td>{{item.assigned.join(', ') || "None"}}</td>
|
||||
<td>{{item.endDay}} --- {{item.endDay + (item.permittedDelay || 0) + (item.chainedDelay || 0)}}</td>
|
||||
<td>{{item.permittedDelay || 0}}</td>
|
||||
<td>{{item.chainedDelay || 0}}</td>
|
||||
|
Loading…
Reference in New Issue
Block a user