module a7 import StdEnv import qualified Data.List as List import Data.Func import Control.Applicative import iTasks :: Job = { id :: Int , jobName :: String , skills :: [Skill] , blocked :: Bool , children :: [Job] } :: Skill = Programming | Design | Testing :: Worker = { username :: String , password :: String , skills :: [Skill] , loggedIn :: Bool } instance == Worker where == w1 w2 = w1.Worker.username == w2.Worker.username instance == Skill where == s1 s2 = s1 === s2 instance == Job where == s1 s2 = s1.jobName == s2.jobName derive class iTask Worker, Skill, Job derive JSONEncode Set derive JSONDecode Set derive gText Set derive gEditor Set derive gDefault Set usersStore :: Shared [Worker] usersStore = sharedStore "Users" [{Worker|username="mart",password="mart",loggedIn=False,skills=[Design,Testing]}] userStore :: String -> Shared Worker userStore u = mapReadWriteError (\wl->case filter (\w->w.Worker.username == u) wl of [u] = Ok u u = Error (exception ("worker not found: " +++ toSingleLineText u)) ,\nw wl->Ok $ Just [nw:filter (\w->w.Worker.username <> u) wl] ) usersStore jobsStore :: Shared [Job] jobsStore = sharedStore "Jobs" [{id=1,jobName="Testing",skills=[Testing],children=[],blocked=False} ,{id=2,jobName="Bigjob",skills=[Testing],blocked=False,children= [{id=3,jobName="subjob1",skills=[Testing],children=[],blocked=False} ,{id=4,jobName="subjob1",skills=[Testing],children=[],blocked=False} ]} ] jobStore :: Int -> Shared Job jobStore i = mapReadWriteError (findJob i ,\nj jl->Ok $ Just $ map (updateJob nj) jl ) jobsStore where findJob i [] = Error (exception "Job not found") findJob i [j=:{Job|id}:_] | id == i = Ok j findJob i [j:js] = case findJob i j.Job.children of Error e = findJob i js Ok u = Ok u updateJob nj j=:{Job|id} | id == i = nj updateJob nj j = {Job|j & children=map (updateJob nj) j.Job.children} removeJob :: Int [Job] -> [Job] removeJob i [] = [] removeJob i [j=:{Job|id}:js] | i == id = js removeJob i [j:js] = [{Job|j & children=removeJob i j.Job.children}:removeJob i js] jobID :: Shared Int jobID = sharedStore "JobIDS" 4 Start w = doTasks ((login -||- register <<@ ArrangeWithTabs False) >>- work) w register :: Task Worker register = tune (Title "Register") $ enterInformation "Enter credentials" [EnterUsing id credentialEditor] -&&- enterInformation "Enter Skills" [] >>= \((u, p),s)->get usersStore @ filter (\a->a.Worker.username==u) >>- \exists->case exists of [] = let user = {loggedIn=True,username=u,password=p,skills=removeDup s} in upd (\l->[user:l]) usersStore >>| treturn user _ = viewInformation "User already exists" [] () >>| register login :: Task Worker login = tune (Title "Login") $ enterInformation "Enter credentials" [EnterUsing id credentialEditor] >>= \(u,p)->get usersStore @ filter (\a->a.Worker.username==u && a.Worker.password==p) >>- \u->case u of [] = viewInformation "User not found or incorrect password" [] () >>| login [{loggedIn=True}] = viewInformation "User is already logged in" [] () >>| login [u] = upd (\w->{w & loggedIn=True}) (userStore u.Worker.username) credentialEditor = panel2 (textField <<@ labelAttr "Username") (passwordField <<@ labelAttr "Password") work :: Worker -> Task [()] work {Worker|username} = allTasks [ viewJobs , createNewJobs , updateSkills ] <<@ Title ("Welcome " +++ username) <<@ ArrangeWithTabs False where viewJobs = tune (Title "View jobs") $ editSelectionWithShared "Select a job" False (SelectInTree toCN fromSel) (jobsStore >*< userStore username) (\_->[]) >^* [OnAction (Action "Execute") $ ifValue (\j->j=:[_]) \[j]-> upd (\j->{j & blocked=True}) (jobStore j.Job.id) >>| viewSharedInformation "Job" [] (jobStore j.Job.id) >>* [OnAction (Action "Finish") $ always $ upd (removeJob j.Job.id) jobsStore ,OnAction (Action "Split") $ always $ enterInformation "Enter sub jobs" [EnterUsing id (gEditor{|*->*|} jobEditor gText{|*|} JSONEncode{|*|} JSONDecode{|*|})] >>= \sjs->sequence (take (length sjs) (repeat (upd inc jobID))) >>= \ids->upd (\j->{Job|j & blocked=False,children=[{Job|id=i,jobName=n,skills=s,blocked=False,children=[]}\\(n,s)<-sjs & i<-ids]}) (jobStore j.Job.id) @! [] ,OnAction (Action "Cancel") $ always $ upd (\j->{j & blocked=False}) (jobStore j.Job.id) @! [] ] ] @! () toCN ::([Job],Worker) -> [ChoiceNode] toCN (jobs, worker) = [ {id=if (job.Job.blocked || not (job.Job.children =: []) || not (matchSkills job)) (~job.Job.id) job.Job.id ,label=job.Job.jobName +++ "(" +++ toSingleLineText job.Job.skills +++ ")" ,icon=if (job.Job.blocked || not (matchSkills job)) (Just "document-error") Nothing ,expanded=True ,children=toCN (job.Job.children, worker) } \\job<-jobs ] where matchSkills job = 'List'.difference job.Job.skills worker.Worker.skills == [] fromSel :: ([Job],Worker) [Int] -> [Job] fromSel (jobs,w) ids = [j\\j<-jobs | isMember j.Job.id ids] ++ flatten [fromSel (j.Job.children, w) ids\\j<-jobs] createNewJobs = tune (Title "Create new jobs") $ forever $ enterInformation "Enter job" [EnterUsing id jobEditor] >>= \(name, skills)->upd inc jobID >>= \i->upd ((++) [{Job|id=i,skills=skills,jobName=name,blocked=False,children=[]}]) jobsStore @! () jobEditor :: Editor (String, [Skill]) jobEditor = panel2 (gEditor{|*|} <<@ labelAttr "Name") (gEditor{|*|} <<@ labelAttr "Skills") updateSkills = tune (Title "Edit skills") $ updateSharedInformation "Skills" [UpdateAs (\w->w.Worker.skills) (\w s->{Worker|w & skills=s})] (userStore username) @! ()