Skip to content

Instantly share code, notes, and snippets.

@Neftedollar
Created April 2, 2018 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Neftedollar/75af23e2ac4fdf284a33a295c81fdea6 to your computer and use it in GitHub Desktop.
Save Neftedollar/75af23e2ac4fdf284a33a295c81fdea6 to your computer and use it in GitHub Desktop.
elmish cmds
module Server =
open Shared
open Fable.Remoting.Client
/// A proxy you can use to talk to server directly
let api : ICounterProtocol =
Proxy.createWithBuilder<ICounterProtocol> Route.builder
let init () : Model * Cmd<Msg> =
let model = Model.Default
let reposCmd =
Cmd.ofAsync
Server.api.getRepositories
()
(Ok >> InitRepos)
(Error >> InitRepos)
let counterCmd =
Cmd.ofAsync
Server.api.getInitCounter
()
(Ok >> Init)
(Error >> Init)
model, Cmd.batch( [counterCmd;reposCmd] )
module GitHub =
let client = ProductHeaderValue "fsharplang-ru-site" |> GitHubClient
let getRepositorys ():Task<Shared.Repositorys> = task {
let! repos = client.Repository.GetAllForOrg "fsharplang-ru"
do! Task.Delay 10000
return repos |> Seq.map (fun x -> x.Name) |> Array.ofSeq
}
let getInitCounter () : Task<Counter> = task {
do! Task.Delay 3000
return 42
}
let webApp : HttpHandler =
let counterProcotol =
{
getInitCounter = getInitCounter >> Async.AwaitTask
getRepositories = GitHub.getRepositorys >> Async.AwaitTask
}
type Counter = int
type Repositorys = string array
type Model =
{
Counter: Counter option
Repositorys : Repositorys
} with static member Default = {
Counter = None
Repositorys = [||]
}
module Route =
/// Defines how routes are generated on server and mapped from client
let builder typeName methodName =
sprintf "/api/%s/%s" typeName methodName
/// A type that specifies the communication protocol for client and server
/// Every record field must have the type : 'a -> Async<'b> where 'a can also be `unit`
/// Add more such fields, implement them on the server and they be directly available on client
type ICounterProtocol =
{
getInitCounter : unit -> Async<Counter>
getRepositories : unit -> Async<Repositorys>
}
let update (msg : Msg) (model : Model) : Model * Cmd<Msg> =
let model' =
match model.Counter, msg with
| Some x, Increment -> { model with Counter = Some (x + 1) }
| Some x, Decrement -> { model with Counter =Some (x - 1) }
| None, Init (Ok x) -> { model with Counter = Some x }
| _ , InitRepos (Ok x) -> { model with Repositorys = x }
| _ -> model
model', Cmd.none
let showCounter = function
| Some x -> string x
| None -> "Loading..."
let showRepos (a:Repositorys) =
match a with
| [||] -> "Loading..."
| _ -> System.String.Join(", " , a)
let button txt onClick =
Button.button
[ Button.IsFullwidth
Button.Color IsPrimary
Button.OnClick onClick ]
[ str txt ]
let view (model : Model) (dispatch : Msg -> unit) =
div []
[ Navbar.navbar [ Navbar.Color IsPrimary ]
[ Navbar.Item.div [ ]
[ Heading.h2 [ ]
[ str "SAFE Template" ] ] ]
Container.container []
[ Content.content [ Content.CustomClass Bulma.Properties.Alignment.HasTextCentered ]
[ Heading.h3 [] [ str ("Press buttons to manipulate counter: " + showCounter model.Counter ) ] ]
Columns.columns []
[ Column.column [] [ button "-" (fun _ -> dispatch Decrement) ]
Column.column [] [ button "+" (fun _ -> dispatch Increment) ] ] ]
Footer.footer [ ]
[ Content.content [ Content.CustomClass Bulma.Properties.Alignment.HasTextCentered ]
[
safeComponents
div [] [ showRepos model.Repositorys |> str ]
] ] ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment