module projectAdmin
import StdEnv, StdHtml
:: Tree = Leaf | Branch Tree Tree
L = Leaf
Bra = Branch
derive gForm Worker, Project, DailyWork, ProjectPlan, Status, WorkerPlan
derive gUpd Worker, Project, DailyWork, ProjectPlan, Status, WorkerPlan, []
derive gPrint Worker, Project, DailyWork, ProjectPlan, Status, WorkerPlan
derive gParse Worker, Project, DailyWork, ProjectPlan, Status, WorkerPlan
derive gerda Worker, Project, DailyWork, ProjectPlan, Status, WorkerPlan
Start world = doHtmlServer ProjectAdminPage world
//Start world = doHtml ProjectAdminPage world
:: Project = { plan :: ProjectPlan
, status :: Status
, members :: [Worker]
}
:: ProjectPlan = { name :: String
, hours :: Int
}
:: Status = { total :: Int
, left :: Int
}
:: Worker = { name :: String
, status :: Status
, work :: [Work]
}
:: Work :== (HtmlDate,Int)
:: WorkerPlan = { project :: ProjectList
, name :: String
, hours :: Int
}
:: DailyWork = { projectId :: ProjectList
, myName :: WorkersList
, date :: HtmlDate
, hoursWorked :: Int
}
:: ProjectList :== PullDownMenu
:: WorkersList :== PullDownMenu
// Form creation/update functions:
adminForm :: ([Project] -> [Project]) *HSt -> (Form [Project], *HSt)
adminForm update hst = mkStoreForm (Init, pdFormId "admin" initProjects) update hst
projectForm :: *HSt -> (Form ProjectPlan, *HSt)
projectForm hst = mkEditForm (Init, nFormId "project" (initProjectPlan "" 0)) hst
workerForm :: (WorkerPlan -> WorkerPlan) *HSt -> (Form WorkerPlan, *HSt)
workerForm update hst = mkStoreForm (Init, nFormId "worker" (initWorkerPlan "" 0 0 initProjects)) update hst
hoursForm :: (DailyWork -> DailyWork) *HSt -> (Form DailyWork, *HSt)
hoursForm update hst = mkStoreForm (Init, nFormId "hours" (initDailyWork 0 0 initProjects)) update hst
buttonsForm :: DailyWork WorkerPlan ProjectPlan *HSt -> (Form ([Project] -> [Project]), *HSt)
buttonsForm daylog workplan project hst = ListFuncBut (Init, nFormId "buttons" myButtons) hst
where
myButtons = [ (LButton defpixel "addProject", addNewProject project )
, (LButton defpixel "addWorker", addNewWorkplan workplan)
, (LButton defpixel "addHours", addDailyWork daylog )
]
addNewProject :: ProjectPlan -> [Project] -> [Project]
addNewProject {ProjectPlan|name,hours} = flip (:^) (initProject name hours)
addNewWorkplan :: WorkerPlan -> [Project] -> [Project]
addNewWorkplan worker=:{project,name,hours}
= updateElt (\{plan={ProjectPlan|name,hours}} -> name == toString project)
(\p -> {p & members = [initWorker name hours:p.members]})
addDailyWork :: DailyWork [Project] -> [Project]
addDailyWork daylog projects
| daylog.hoursWorked == 0 || toString daylog.myName == "" || isEmpty projects
= projects
| otherwise = updateAt (toInt daylog.projectId) updatedProject projects
where
{status,plan=plan=:{ProjectPlan|hours},members}
= projects!!(toInt daylog.projectId)
totalHoursSpent = status.total + daylog.hoursWorked
remainingHours = hours - totalHoursSpent
updatedProject = { status = initStatus remainingHours totalHoursSpent
, members = addDay daylog members
, plan = plan
}
nworklog = { name = daylog.myName
, work = [(daylog.date,daylog.hoursWorked)]
, status = initStatus 0 0
}
addDay :: DailyWork -> [Worker] -> [Worker]
addDay nwork=:{myName,date,hoursWorked}
= updateElt (\owork=:{Worker|name} -> name == toString myName)
(\owork=:{Worker|status,work}
-> {owork & work = work ++ [(date,hoursWorked)]
, status = {status & total=status.total+hoursWorked
, left =status.left -hoursWorked
} })
ProjectAdminPage :: *HSt -> (Html,*HSt)
ProjectAdminPage hst
= updatePage (updateForms hst)
where
updateForms :: *HSt -> ((Form [Project],Form ProjectPlan,Form WorkerPlan,Form DailyWork,Form ([Project] -> [Project])),*HSt)
updateForms hst
// # (adminF, hst) = adminForm id hst
# (projectF,hst) = projectForm hst
# (workerF, hst) = workerForm id hst
# (hoursF, hst) = hoursForm id hst
# (buttonsF,hst) = buttonsForm hoursF.value workerF.value projectF.value hst
# (adminF, hst) = adminForm buttonsF.value hst
# (hoursF, hst) = hoursForm (adjDailyWork adminF.value) hst
# (workerF, hst) = workerForm (adjWorkers adminF.value) hst
= ((adminF,projectF,workerF,hoursF,buttonsF),hst)
where
adjDailyWork :: [Project] DailyWork -> DailyWork
adjDailyWork projects daylog=:{projectId}
= { daylog & projectId = addProjectList projects projectId
, myName = initWorkersList (toInt daylog.myName) (toInt projectId) projects
}
adjWorkers :: [Project] WorkerPlan -> WorkerPlan
adjWorkers projects worker = {worker & project = addProjectList projects worker.project}
addProjectList :: [Project] PullDownMenu -> PullDownMenu
addProjectList projects (PullDown dim (i,_)) = PullDown dim (i,[name \\ {plan={ProjectPlan|name}} <- projects])
updatePage :: ((Form [Project],Form ProjectPlan,Form WorkerPlan,Form DailyWork,Form ([Project] -> [Project])),*HSt) -> (Html,*HSt)
updatePage ((adminF,projectF,workerF,hoursF,buttonsF),hst)
= mkHtml "table test"
[ H1 [] "Project Administration"
, STable []
[ [ STable []
[ [lTxt "Add New Project:"], projectF.form,[projectButton]
, [lTxt "Add New Worker:"], workerF.form, [workerButton]
: if no_projects []
[ [lTxt "Administrate Worked Hours:"],hoursF.form, [hoursButton]]
]
: if no_projects []
[ STable []
[ [ lTxt "Current Status of Project:" ]
, [ toHtml (adminF.value!!(toInt hoursF.value.projectId)) ]
]
]]
]
] hst
where
no_projects = isEmpty adminF.value
lTxt s = B [] s
[projectButton,workerButton,hoursButton:_] = buttonsF.form
// specializations
// List elements need to be displayed below each other, left aligned:
gForm {|[]|} gHa (init,formid) hst
= case formid.ival of
[]
= ({changed = False, value = [], form =[EmptyBody]},hst)
[x:xs]
# (formx, hst) = gHa (init,reuseFormId formid x) hst
# (formxs,hst) = gForm {|*->*|} gHa (init,setFormId formid xs) hst
= ({changed = False, value = [x:xs], form = [formx.form <||> formxs.form]},hst)
// Initial values of the work administration's data structures:
initProjects :: [Project]
initProjects = []
initProject :: String Int -> Project
initProject name hours
= { plan = initProjectPlan name hours
, status = initStatus hours 0
, members = [] }
initProjectPlan :: String Int -> ProjectPlan
initProjectPlan name hours
= {ProjectPlan
| name = name
, hours = hours }
initStatus :: Int Int -> Status
initStatus todo done
= { total = done
, left = todo }
initWorkerPlan :: String Int Int [Project] -> WorkerPlan
initWorkerPlan name hours i projects
= { project = initProjectList i projects
, name = name
, hours = hours }
initWorker :: String Int -> Worker
initWorker name hours
= { name = name
, status = initStatus hours 0
, work = [] }
initDailyWork :: Int Int [Project] -> DailyWork
initDailyWork i j projects
= { myName = initWorkersList i j projects
, projectId = initProjectList i projects
, date = initDate
, hoursWorked = 0 }
initDate :: HtmlDate
initDate = Date 1 1 2005
initWorkersList :: Int Int [Project] -> PullDownMenu
initWorkersList i j [] = PullDown (1,defpixel) (0,[])
initWorkersList i j projects = PullDown (1,defpixel) (i,[name \\ {Worker|name} <- (projects!!j).members])
initProjectList :: Int [Project] -> PullDownMenu
initProjectList i projects = PullDown (1,defpixel) (i,[name \\ {plan={ProjectPlan|name}} <- projects])
// Useful list operations:
updateElt :: (a -> Bool) (a -> a) [a] -> [a]
updateElt c f [] = []
updateElt c f [a:as]
| c a = [f a:as]
| otherwise = [a:updateElt c f as]
updateElts :: (a -> Bool) (a -> a) [a] -> [a]
updateElts c f [] = []
updateElts c f [a:as]
| c a = [f a:updateElts c f as]
| otherwise = [ a:updateElts c f as]
(^:) infixr 5 :: a [a] -> [a]
(^:) a as = [a:as]
(:^) infixl 5 :: [a] a -> [a]
(:^) as a = as ++ [a]
// Monadic digression:
:: StM st a :== st -> .(!a,!st)
(>>=) infixr 5 :: !u:(StM .st .a) !v:(.a -> .(StM .st .b)) -> w:(StM .st .b), [w<=u,w<=v]
(>>=) fA to_mB = mbind` fA to_mB
where
mbind` fA to_mB st
# (a,st) = fA st
= to_mB a st
(>>-) infixr 5 :: !u:(StM .st .a) !v:(StM .st .b) -> w:(StM .st .b), [w <= u,w <= v]
(>>-) fA fB = mbind_` fA fB
where
mbind_` fA fB st
# (_,st) = fA st
= fB st
mreturn :: !u:a -> v:(StM .st u:a), [v<=u]
mreturn x = mreturn` x
where
mreturn` x st = (x,st)