From 665694bd746e423f976688d18f8a8a00a9399f3a Mon Sep 17 00:00:00 2001 From: Aaron Bieber Date: Thu, 18 Apr 2024 08:03:07 -0600 Subject: [PATCH] add table views for all the various things --- assets/index.html | 23 ++- assets/main.min.js | 2 +- data/queries.sql.go | 17 ++ elm.json | 1 + handlers.go | 44 +++++ main.go | 2 + queries.sql | 7 + src/Ignores.elm | 39 +++++ src/Links.elm | 50 ++++++ src/Main.elm | 405 +++++++++++++++++++++++++++++--------------- src/Watches.elm | 78 +++++++++ 11 files changed, 525 insertions(+), 143 deletions(-) create mode 100644 src/Ignores.elm create mode 100644 src/Links.elm create mode 100644 src/Watches.elm diff --git a/assets/index.html b/assets/index.html index b7eb222..deada59 100644 --- a/assets/index.html +++ b/assets/index.html @@ -71,7 +71,7 @@ .form-container { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(4, 1fr); } .form-content { @@ -81,6 +81,26 @@ color: red; } + table { + border: 1px solid #dedeff; + } + + table tr td { + padding: 5px; + } + + table th { + background-color: #dedeff; + } + + table tr:nth-child(even) { + background-color: #f6f8f9; + } + + table tr:nth-child(odd) { + background-color: #fff; + } + header { padding: 0 !important; } @@ -94,7 +114,6 @@ } footer { - text-align: center; } diff --git a/assets/main.min.js b/assets/main.min.js index eeb2436..9b2299e 100644 --- a/assets/main.min.js +++ b/assets/main.min.js @@ -1 +1 @@ -!function(B){"use strict";function n(n,r,t){return t.a=n,t.f=r,t}function r(t){return n(2,t,function(r){return function(n){return t(r,n)}})}function t(e){return n(3,e,function(t){return function(r){return function(n){return e(t,r,n)}}})}function D(u){return n(4,u,function(e){return function(t){return function(r){return function(n){return u(e,t,r,n)}}}})}function R(a){return n(5,a,function(u){return function(e){return function(t){return function(r){return function(n){return a(u,e,t,r,n)}}}}})}function M(i){return n(6,i,function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return i(a,u,e,t,r,n)}}}}}})}function F(o){return n(7,o,function(i){return function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return o(i,a,u,e,t,r,n)}}}}}}})}function b(n,r,t){return 2===n.a?n.f(r,t):n(r)(t)}function s(n,r,t,e){return 3===n.a?n.f(r,t,e):n(r)(t)(e)}function v(n,r,t,e,u){return 4===n.a?n.f(r,t,e,u):n(r)(t)(e)(u)}function d(n,r,t,e,u,a){return 5===n.a?n.f(r,t,e,u,a):n(r)(t)(e)(u)(a)}function z(n,r,t,e,u,a,i){return 6===n.a?n.f(r,t,e,u,a,i):n(r)(t)(e)(u)(a)(i)}function H(n,r,t,e,u,a,i,o){return 7===n.a?n.f(r,t,e,u,a,i,o):n(r)(t)(e)(u)(a)(i)(o)}function P(n,r){for(var t,e=[],u=Y(n,r,0,e);u&&(t=e.pop());u=Y(t.a,t.b,0,e));return u}function Y(n,r,t,e){if(n!==r){if("object"!=typeof n||null===n||null===r)return"function"==typeof n&&Z(5),!1;if(100i)return u}var v=t.$;if(4===v){for(var d=t.k;4===d.$;)d=d.k;return n(r,d,e,u,a+1,i,r.elm_event_node_ref)}var l=t.e;var $=r.childNodes;for(var h=0;hi))return u;a=p}return u}(n,r,t,0,0,r.b,e)}function br(n,r,t,e){return 0===t.length?n:(sr(n,r,t,e),vr(n,t))}function vr(n,r){for(var t=0;t "),x(n.q),b(yu,$([Ze({$:5,a:n.ag})]),$([x(" ×")]))])),b(Cu,l,b(Yt,Kr,n.aG))]))]))])):x("")},Ju={$:16},qu=r(function(n,r){return b(O,l,$([s(ou,"Watches",Ju,b(O,l,$([d(hu,"Item: ","some string...","name",n.C.q,function(n){return{$:8,a:e(r,{q:n})}}),d(hu,"Repository: ","NixOS/nixpkgs","repo",n.C.T,function(n){return{$:8,a:e(r,{T:n})}})])))]))}),fn=kn({b4:function(n){return{a:Be,b:Xt($([Oe,xe]))}},cy:function(n){return De},cC:Q,cD:function(t){return b(O,l,$([b(Ve,l,$([b(O,$([S("grid")]),$([b(O,$([S("col")]),$([function(n){return b(O,l,$([b(ku,b(qu,n,n.C),b(tu,$([Ze(Eu)]),$([x(" ⟳")]))),n.aq.b?b(Cu,l,b(Yt,Nu,n.aq)):x("No watches found!")]))}(t)])),b(O,$([S("col")]),$([function(n){return b(O,l,$([b(ku,b(pu,n,n.u),b(tu,$([Ze(ru)]),$([x(" ⟳")]))),n.aj.b?b(O,$([S("icon-grid")]),b(Yt,ju,n.aj)):x("No links found!")]))}(t)]))])),b(O,$([S("grid")]),$([function(){var n,r=t.p;return 3===r.$?(r=r.a,b(O,$([(n=$([{a:"error",b:!0}]),S(b(st," ",b(Yt,Ot,b(Ie,We,n)))))]),$([x(r)]))):x("")}()]))])),b(Xe,l,$([b(Ue,l,$([b(nu,l,$([b(Ye,l,$([x("Maintenence")]))])),b(Ge,$([Ze(Pe)]),$([x("Update Icons")]))]))]))]))}});an={Main:{init:fn(Ft(0))(0)}},B.Elm?function n(r,t){for(var e in t)e in r?"init"==e?Z(6):n(r[e],t[e]):r[e]=t[e]}(B.Elm,an):B.Elm=an}(this); \ No newline at end of file +!function(W){"use strict";function R(n,r,t){return t.a=n,t.f=r,t}function r(t){return R(2,t,function(r){return function(n){return t(r,n)}})}function t(e){return R(3,e,function(t){return function(r){return function(n){return e(t,r,n)}}})}function n(u){return R(4,u,function(e){return function(t){return function(r){return function(n){return u(e,t,r,n)}}}})}function H(a){return R(5,a,function(u){return function(e){return function(t){return function(r){return function(n){return a(u,e,t,r,n)}}}}})}function F(c){return R(6,c,function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return c(a,u,e,t,r,n)}}}}}})}function q(i){return R(7,i,function(c){return function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return i(c,a,u,e,t,r,n)}}}}}}})}function s(n,r,t){return 2===n.a?n.f(r,t):n(r)(t)}function b(n,r,t,e){return 3===n.a?n.f(r,t,e):n(r)(t)(e)}function x(n,r,t,e,u){return 4===n.a?n.f(r,t,e,u):n(r)(t)(e)(u)}function v(n,r,t,e,u,a){return 5===n.a?n.f(r,t,e,u,a):n(r)(t)(e)(u)(a)}function D(n,r,t,e,u,a,c){return 6===n.a?n.f(r,t,e,u,a,c):n(r)(t)(e)(u)(a)(c)}function G(n,r,t,e,u,a,c,i){return 7===n.a?n.f(r,t,e,u,a,c,i):n(r)(t)(e)(u)(a)(c)(i)}function V(n,r){for(var t,e=[],u=I(n,r,0,e);u&&(t=e.pop());u=I(t.a,t.b,0,e));return u}function I(n,r,t,e){if(n!==r){if("object"!=typeof n||null===n||null===r)return"function"==typeof n&&tn(5),!1;if(100c)return u}var v=t.$;if(4===v){for(var l=t.k;4===l.$;)l=l.k;return n(r,l,e,u,a+1,c,r.elm_event_node_ref)}var d=t.e;var $=r.childNodes;for(var h=0;hc))return u;a=p}return u}(n,r,t,0,0,r.b,e)}function mr(n,r,t,e){return 0===t.length?n:(pr(n,r,t,e),wr(n,t))}function wr(n,r){for(var t=0;t "),B(n.bl),s(gu,d([S({$:5,a:n.cc})]),d([B(" ×")]))])),s(pa,l,s(_,vt,n.bC))]))]))])):B("")},Oa={$:20},ya=r(function(n,r){return s(Y,l,d([b(ra,"Watches",Oa,s(Y,l,d([v(ba,"Item: ","some string...","name",n.B.bl,function(n){return{$:10,a:e(r,{bl:n})}}),v(ba,"Repository: ","NixOS/nixpkgs","repo",n.B.cF,function(n){return{$:10,a:e(r,{cF:n})}})])))]))}),gn=bn({bl:"Action",Y:ln,_:function(n){return s($u,l,d([s(ou,d([S({$:5,a:n.cc})]),d([B("Delete")]))]))}}),_a=(u={aB:d([s(hn,"Name",function(n){return n.bl}),s(hn,"Repo",function(n){return n.cF}),gn]),aW:function(n){return n.bl},aX:function(n){return{$:24,a:n}}},en=u.aX,Q=u.aW,{aB:s(_,function(n){return n},u.aB),a3:rn,aW:Q,aX:en}),X=_n({cf:function(n){return{a:Qe,b:fe(d([Ue,Xe,Pe]))}},cO:function(n){return Ze},cT:un,cU:function(t){return s(Y,l,d([s(Au,l,d([s(Y,d([C("grid")]),d([s(Y,d([C("col")]),d([function(n){return s(Y,l,d([s(da,s(ya,n,n.B),s(Xu,d([S(ga)]),d([B(" ⟳")]))),n.aa.b?s(pa,l,s(_,ka,n.aa)):B("No watches found!")]))}(t)])),s(Y,d([C("col")]),d([function(n){return s(Y,l,d([s(da,s(va,n,n.s),s(Xu,d([S(Uu)]),d([B(" ⟳")]))),n.W.b?s(Y,d([C("icon-grid")]),s(_,ha,n.W)):B("No links found!")]))}(t)]))])),s(Y,d([C("grid")]),d([function(){var n,r=t.i;return 4===r.$?(r=r.a,s(Y,d([(n=d([{a:"error",b:!0}]),C(s(_t," ",s(_,Pt,s(bu,su,n)))))]),d([B(r)]))):B("")}()]))])),s(lu,l,d([s(vu,l,d([s(Lu,l,d([s(iu,l,d([B("Maintenence")]))])),s(Y,l,d([s(ou,d([S(cu)]),d([B("Update Icons")]))])),s(Y,l,d([s(du,l,d([B("Links")])),b(Pu,Nu,t.as,t.W)])),s(Y,l,d([s(du,l,d([B("Watched Items")])),b(Pu,_a,t.az,t.aa)])),s(Y,l,d([s(du,l,d([B("Watched Items Ignores")])),b(Pu,Tu,t.aq,t.ar)]))]))]))]))}});nn={Main:{init:X(re(0))(0)}},W.Elm?function n(r,t){for(var e in t)e in r?"init"==e?tn(6):n(r[e],t[e]):r[e]=t[e]}(W.Elm,nn):W.Elm=nn}(this); \ No newline at end of file diff --git a/data/queries.sql.go b/data/queries.sql.go index 7563534..0d5defc 100644 --- a/data/queries.sql.go +++ b/data/queries.sql.go @@ -175,6 +175,23 @@ func (q *Queries) AddWatchItem(ctx context.Context, arg AddWatchItemParams) (Wat return i, err } +const deleteIgnore = `-- name: DeleteIgnore :exec +delete +from pull_request_ignores +where id = ? + and owner_id = ? +` + +type DeleteIgnoreParams struct { + ID int64 `json:"id"` + OwnerID int64 `json:"owner_id"` +} + +func (q *Queries) DeleteIgnore(ctx context.Context, arg DeleteIgnoreParams) error { + _, err := q.db.ExecContext(ctx, deleteIgnore, arg.ID, arg.OwnerID) + return err +} + const deleteLink = `-- name: DeleteLink :exec delete from links diff --git a/elm.json b/elm.json index eea3262..e887362 100644 --- a/elm.json +++ b/elm.json @@ -6,6 +6,7 @@ "elm-version": "0.19.1", "dependencies": { "direct": { + "billstclair/elm-sortable-table": "1.2.1", "elm/browser": "1.0.2", "elm/core": "1.0.5", "elm/html": "1.0.0", diff --git a/handlers.go b/handlers.go index a4d1676..7fdf777 100644 --- a/handlers.go +++ b/handlers.go @@ -299,6 +299,50 @@ func linksPOST(w http.ResponseWriter, r *http.Request) { } } +func prignoreGET(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + ownerID, ok := ctx.Value(ownerKey).(int64) + if !ok { + http.Error(w, http.StatusText(http.StatusUnprocessableEntity), http.StatusUnprocessableEntity) + return + } + prIgnores, err := app.queries.GetAllPullRequestIgnores(app.ctx, ownerID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + prJson, err := json.Marshal(prIgnores) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Add("Content-type", "application/json") + w.WriteHeader(200) + _, err = w.Write(prJson) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} + +func prignoreDELETE(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + ownerID, ok := ctx.Value(ownerKey).(int64) + if !ok { + http.Error(w, http.StatusText(http.StatusUnprocessableEntity), http.StatusUnprocessableEntity) + return + } + ignoreID, err := strconv.Atoi(chi.URLParam(r, "ignoreID")) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + err = app.queries.DeleteIgnore(app.ctx, data.DeleteIgnoreParams{ID: int64(ignoreID), OwnerID: ownerID}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + func prignorePOST(w http.ResponseWriter, r *http.Request) { d := &data.AddPullRequestIgnoreParams{} if err := render.Decode(r, d); err != nil { diff --git a/main.go b/main.go index f6d9679..6f0911f 100644 --- a/main.go +++ b/main.go @@ -156,6 +156,8 @@ func main() { r.Route("/prignores", func(r chi.Router) { r.Use(render.SetContentType(render.ContentTypeJSON)) r.Post("/", prignorePOST) + r.Get("/", prignoreGET) + r.Delete("/{ignoreID:[0-9]+}", prignoreDELETE) }) r.Route("/icons", func(r chi.Router) { r.Use(IconCacher) diff --git a/queries.sql b/queries.sql index d8b4d22..1a47e2a 100644 --- a/queries.sql +++ b/queries.sql @@ -82,6 +82,13 @@ from pull_requests where id = ? and owner_id = ?; +-- name: DeleteIgnore :exec +delete +from pull_request_ignores +where id = ? + and owner_id = ?; + + -- name: GetAllPullRequestIgnores :many select * from pull_request_ignores diff --git a/src/Ignores.elm b/src/Ignores.elm new file mode 100644 index 0000000..a41f04e --- /dev/null +++ b/src/Ignores.elm @@ -0,0 +1,39 @@ +module Ignores exposing (..) + +import Json.Decode + exposing + ( Decoder + , field + , int + , list + , map5 + , string + ) + + +type alias Ignores = + List Ignore + + +type alias Ignore = + { id : Int + , ownerId : Int + , createdAt : String + , repo : String + , number : Int + } + + +ignoreListDecoder : Decoder Ignores +ignoreListDecoder = + list ignoreDecoder + + +ignoreDecoder : Decoder Ignore +ignoreDecoder = + map5 Ignore + (field "id" int) + (field "owner_id" int) + (field "created_at" string) + (field "repo" string) + (field "number" int) diff --git a/src/Links.elm b/src/Links.elm new file mode 100644 index 0000000..9df0d65 --- /dev/null +++ b/src/Links.elm @@ -0,0 +1,50 @@ +module Links exposing (..) + +import Json.Decode + exposing + ( Decoder + , bool + , field + , int + , list + , map6 + , string + ) + + +type alias Links = + List Link + + +type alias NewLink = + { name : String + , url : String + , shared : Bool + , logo_url : String + } + + +type alias Link = + { id : Int + , createdAt : String + , url : String + , name : String + , logoURL : String + , shared : Bool + } + + +linkListDecoder : Decoder Links +linkListDecoder = + list linkDecoder + + +linkDecoder : Decoder Link +linkDecoder = + map6 Link + (field "id" int) + (field "created_at" string) + (field "url" string) + (field "name" string) + (field "logo_url" string) + (field "shared" bool) diff --git a/src/Main.elm b/src/Main.elm index 08a6231..b635400 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -2,63 +2,25 @@ module Main exposing (..) import Browser import Html exposing (..) -import Html.Attributes exposing (checked, class, classList, href, name, placeholder, src, type_, value) +import Html.Attributes + exposing + ( checked + , class + , classList + , href + , name + , placeholder + , src + , type_ + , value + ) import Html.Events exposing (..) import Http -import Json.Decode as Decode - exposing - ( Decoder - , bool - , field - , int - , list - , map5 - , map6 - , string - ) +import Ignores import Json.Encode as Encode - - -type alias Watches = - List Watch - - -type alias Links = - List Link - - -type alias Link = - { id : Int - , createdAt : String - , url : String - , name : String - , logoURL : String - , shared : Bool - } - - -type alias Watch = - { id : Int - , ownerId : Int - , name : String - , repo : String - , resultCount : Int - , results : List Node - } - - -type alias Node = - { number : Int - , createdAt : String - , repository : RepoInfo - , title : String - , url : String - } - - -type alias RepoInfo = - { nameWithOwner : String - } +import Links +import Table exposing (defaultCustomizations) +import Watches main : Program () Model Msg @@ -78,49 +40,47 @@ type Msg | DeleteLink Int | DeletedWatch (Result Http.Error ()) | DeleteWatch Int - | GotLinks (Result Http.Error (List Link)) - | GotNewLink NewLink - | GotNewWatch NewWatch - | GotWatches (Result Http.Error (List Watch)) + | DeletedIgnore (Result Http.Error ()) + | DeleteIgnore Int + | GotLinks (Result Http.Error Links.Links) + | GotNewLink Links.NewLink + | GotNewWatch Watches.NewWatch + | GotWatches (Result Http.Error Watches.Watches) + | GotIgnores (Result Http.Error Ignores.Ignores) | HideWatchedItem Int String | HidItem (Result Http.Error ()) | Reload | ReloadLinks | ReloadWatches + | ReloadIgnores | SubmitLink | SubmitWatch | FetchIcons | LoadIcons (Result Http.Error ()) + | SetLinkTableState Table.State + | SetWatchTableState Table.State + | SetIgnoreTableState Table.State type Status = Loading - | LoadedWatches (List Watch) - | LoadedLinks (List Link) + | LoadedWatches Watches.Watches + | LoadedIgnores Ignores.Ignores + | LoadedLinks Links.Links | Errored String -type alias NewWatch = - { name : String - , repo : String - } - - -type alias NewLink = - { name : String - , url : String - , shared : Bool - , logo_url : String - } - - type alias Model = - { watches : List Watch - , links : List Link + { watches : Watches.Watches + , links : Links.Links + , ignores : Ignores.Ignores , errors : List String , status : Status - , newlink : NewLink - , newwatch : NewWatch + , newlink : Links.NewLink + , newwatch : Watches.NewWatch + , linkTableState : Table.State + , watchTableState : Table.State + , ignoreTableState : Table.State } @@ -128,6 +88,7 @@ initialModel : Model initialModel = { watches = [] , links = [] + , ignores = [] , errors = [] , status = Loading , newlink = @@ -140,12 +101,15 @@ initialModel = { name = "" , repo = "" } + , linkTableState = Table.initialSort "Created" + , watchTableState = Table.initialSort "Created" + , ignoreTableState = Table.initialSort "Created" } init : () -> ( Model, Cmd Msg ) init _ = - ( initialModel, Cmd.batch [ getLinks, getWatches ] ) + ( initialModel, Cmd.batch [ getLinks, getWatches, getIgnores ] ) hideWatched : Int -> String -> Cmd Msg @@ -222,6 +186,19 @@ deleteLink linkId = } +deleteIgnore : Int -> Cmd Msg +deleteIgnore ignoreId = + Http.request + { url = "/prignores/" ++ String.fromInt ignoreId + , method = "DELETE" + , timeout = Nothing + , tracker = Nothing + , headers = [] + , body = Http.emptyBody + , expect = Http.expectWhatever DeletedIgnore + } + + deleteWatch : Int -> Cmd Msg deleteWatch watchId = Http.request @@ -253,6 +230,9 @@ update msg model = DeleteWatch watchId -> ( model, deleteWatch watchId ) + DeleteIgnore ignoreId -> + ( model, deleteIgnore ignoreId ) + GotNewWatch newwatch -> ( { model | newwatch = newwatch }, Cmd.none ) @@ -283,6 +263,12 @@ update msg model = DeletedWatch (Err _) -> ( { model | status = Errored "Server error deleting watch!" }, Cmd.none ) + DeletedIgnore (Ok _) -> + ( model, getIgnores ) + + DeletedIgnore (Err _) -> + ( { model | status = Errored "Server error deleting ignore!" }, Cmd.none ) + HidItem (Err _) -> ( { model | status = Errored "Server error when hiding a watch item!" }, Cmd.none ) @@ -307,12 +293,18 @@ update msg model = ReloadLinks -> ( model, getLinks ) + ReloadIgnores -> + ( model, getIgnores ) + GotWatches (Err _) -> ( { model | status = Errored "Server error when fetching watches!" }, Cmd.none ) GotLinks (Err _) -> ( { model | status = Errored "Server error when fetching links!" }, Cmd.none ) + GotIgnores (Err _) -> + ( { model | status = Errored "Server error when fetching ignores!" }, Cmd.none ) + GotWatches (Ok watches) -> case watches of _ :: _ -> @@ -340,6 +332,28 @@ update msg model = [] -> ( { model | status = Errored "No Links found" }, Cmd.none ) + GotIgnores (Ok ignores) -> + case ignores of + _ :: _ -> + ( { model + | ignores = ignores + , status = LoadedIgnores ignores + } + , Cmd.none + ) + + [] -> + ( { model | status = Errored "No Watches found" }, Cmd.none ) + + SetLinkTableState newState -> + ( { model | linkTableState = newState }, Cmd.none ) + + SetWatchTableState newState -> + ( { model | watchTableState = newState }, Cmd.none ) + + SetIgnoreTableState newState -> + ( { model | ignoreTableState = newState }, Cmd.none ) + subscriptions : Model -> Sub Msg subscriptions _ = @@ -381,18 +395,181 @@ view model = , footer [] [ details [] [ summary [] - [ b [] [ text "Maintenence" ] ] - , button [ onClick FetchIcons ] [ text "Update Icons" ] + [ b [] [ text "Maintenence" ] + ] + , div [] + [ button [ onClick FetchIcons ] [ text "Update Icons" ] + ] + , div [] + [ h3 [] [ text "Links" ] + , Table.view linkTableConfig model.linkTableState model.links + ] + , div [] + [ h3 [] [ text "Watched Items" ] + , Table.view watchTableConfig model.watchTableState model.watches + ] + , div [] + [ h3 + [] + [ text "Watched Items Ignores" ] + , Table.view ignoreTableConfig model.ignoreTableState model.ignores + ] ] ] ] +shareTxt : Links.Link -> Table.HtmlDetails Msg +shareTxt link = + if link.shared then + Table.HtmlDetails [] + [ text "Yes" ] + + else + Table.HtmlDetails [] + [ text "No" ] + + +shareColumn : Table.Column Links.Link Msg +shareColumn = + Table.veryCustomColumn + { name = "Shared" + , viewData = \data -> shareTxt data + , sorter = Table.unsortable + } + + +linkTimeColumn : Table.Column Links.Link Msg +linkTimeColumn = + Table.customColumn + { name = "Created" + , viewData = .createdAt + , sorter = Table.decreasingOrIncreasingBy .createdAt + } + + +deleteLinkColumn : Table.Column Links.Link Msg +deleteLinkColumn = + Table.veryCustomColumn + { name = "Action" + , viewData = linkDeleteView + , sorter = Table.unsortable + } + + +linkTableConfig : Table.Config Links.Link Msg +linkTableConfig = + Table.customConfig + { toId = .name + , toMsg = SetLinkTableState + , columns = + [ Table.stringColumn "Name" .name + , Table.stringColumn "URL" .url + , shareColumn + , Table.stringColumn "Logo URL" .logoURL + , linkTimeColumn + , deleteLinkColumn + ] + , customizations = defaultCustomizations + } + + +linkDeleteView : Links.Link -> Table.HtmlDetails Msg +linkDeleteView { id } = + Table.HtmlDetails [] + [ button + [ onClick (DeleteLink id) ] + [ text "Delete" ] + ] + + +watchTableConfig : Table.Config Watches.Watch Msg +watchTableConfig = + Table.config + { toId = .name + , toMsg = SetWatchTableState + , columns = + [ Table.stringColumn "Name" .name + , Table.stringColumn "Repo" .repo + , deleteWatchColumn + ] + } + + +deleteWatchColumn : Table.Column Watches.Watch Msg +deleteWatchColumn = + Table.veryCustomColumn + { name = "Action" + , viewData = watchDeleteView + , sorter = Table.unsortable + } + + +watchDeleteView : Watches.Watch -> Table.HtmlDetails Msg +watchDeleteView { id } = + Table.HtmlDetails [] + [ button + [ onClick (DeleteWatch id) ] + [ text "Delete" ] + ] + + +ignoreTimeColumn : Table.Column Ignores.Ignore Msg +ignoreTimeColumn = + Table.customColumn + { name = "Created" + , viewData = .createdAt + , sorter = Table.decreasingOrIncreasingBy .createdAt + } + + +deleteIgnoreColumn : Table.Column Ignores.Ignore Msg +deleteIgnoreColumn = + Table.veryCustomColumn + { name = "Action" + , viewData = ignoreDeleteView + , sorter = Table.unsortable + } + + +ignoreDeleteView : Ignores.Ignore -> Table.HtmlDetails Msg +ignoreDeleteView { id } = + Table.HtmlDetails [] + [ button + [ onClick (DeleteIgnore id) ] + [ text "Delete" ] + ] + + +ignoreTableConfig : Table.Config Ignores.Ignore Msg +ignoreTableConfig = + Table.customConfig + { toId = .createdAt + , toMsg = SetIgnoreTableState + , columns = + [ Table.intColumn "ID" .id + , Table.stringColumn "Repo" .repo + , Table.intColumn "Number" .number + , ignoreTimeColumn + , deleteIgnoreColumn + ] + , customizations = defaultCustomizations + } + + +getIgnores : Cmd Msg +getIgnores = + Http.get + { url = "/prignores" + , expect = Http.expectJson GotIgnores Ignores.ignoreListDecoder + } + + getLinks : Cmd Msg getLinks = Http.get { url = "/links" - , expect = Http.expectJson GotLinks linkListDecoder + , expect = Http.expectJson GotLinks Links.linkListDecoder } @@ -400,11 +577,11 @@ getWatches : Cmd Msg getWatches = Http.get { url = "/watches" - , expect = Http.expectJson GotWatches watchListDecoder + , expect = Http.expectJson GotWatches Watches.watchListDecoder } -watchForm : Model -> NewWatch -> Html Msg +watchForm : Model -> Watches.NewWatch -> Html Msg watchForm model newwatch = div [] [ createForm "Watches" @@ -418,7 +595,7 @@ watchForm model newwatch = ] -linkForm : Model -> NewLink -> Html Msg +linkForm : Model -> Links.NewLink -> Html Msg linkForm model newlink = div [] [ createForm "Links" @@ -514,7 +691,7 @@ viewWatches model = ] -viewLink : Link -> Html Msg +viewLink : Links.Link -> Html Msg viewLink link = div [] [ div [ class "icon" ] @@ -532,7 +709,7 @@ viewLink link = ] -viewWatch : Watch -> Html Msg +viewWatch : Watches.Watch -> Html Msg viewWatch watch = case watch.results of [] -> @@ -555,7 +732,7 @@ viewWatch watch = ] -viewResult : Node -> Html Msg +viewResult : Watches.Node -> Html Msg viewResult node = li [] [ a [ href node.url ] [ text (String.fromInt node.number) ] @@ -564,55 +741,3 @@ viewResult node = , text " :: " , text node.title ] - - - --- DECODERS - - -linkListDecoder : Decoder (List Link) -linkListDecoder = - list linkDecoder - - -linkDecoder : Decoder Link -linkDecoder = - map6 Link - (field "id" int) - (field "created_at" string) - (field "url" string) - (field "name" string) - (field "logo_url" string) - (field "shared" bool) - - -watchListDecoder : Decoder (List Watch) -watchListDecoder = - list watchDecoder - - -watchDecoder : Decoder Watch -watchDecoder = - map6 Watch - (field "id" int) - (field "owner_id" int) - (field "name" string) - (field "repo" string) - (field "result_count" int) - (field "results" <| list resultsDecoder) - - -resultsDecoder : Decoder Node -resultsDecoder = - map5 Node - (field "number" int) - (field "createdAt" string) - (field "repository" repoInfoDecoder) - (field "title" string) - (field "url" string) - - -repoInfoDecoder : Decoder RepoInfo -repoInfoDecoder = - Decode.map RepoInfo - (field "nameWithOwner" string) diff --git a/src/Watches.elm b/src/Watches.elm new file mode 100644 index 0000000..5d8bb33 --- /dev/null +++ b/src/Watches.elm @@ -0,0 +1,78 @@ +module Watches exposing (..) + +import Json.Decode as Decode + exposing + ( Decoder + , field + , int + , list + , map5 + , map6 + , string + ) + + +type alias NewWatch = + { name : String + , repo : String + } + + +type alias Watches = + List Watch + + +type alias Watch = + { id : Int + , ownerId : Int + , name : String + , repo : String + , resultCount : Int + , results : List Node + } + + +type alias RepoInfo = + { nameWithOwner : String + } + + +type alias Node = + { number : Int + , createdAt : String + , repository : RepoInfo + , title : String + , url : String + } + + +watchListDecoder : Decoder Watches +watchListDecoder = + list watchDecoder + + +watchDecoder : Decoder Watch +watchDecoder = + map6 Watch + (field "id" int) + (field "owner_id" int) + (field "name" string) + (field "repo" string) + (field "result_count" int) + (field "results" <| list resultsDecoder) + + +resultsDecoder : Decoder Node +resultsDecoder = + map5 Node + (field "number" int) + (field "createdAt" string) + (field "repository" repoInfoDecoder) + (field "title" string) + (field "url" string) + + +repoInfoDecoder : Decoder RepoInfo +repoInfoDecoder = + Decode.map RepoInfo + (field "nameWithOwner" string)