Version 2.1 #41
@ -52,12 +52,14 @@ let displayChapterTests = testList "DisplayChapter.FromChapter" [
|
|||||||
{ StartTime = Duration.FromSeconds 7201.43242
|
{ StartTime = Duration.FromSeconds 7201.43242
|
||||||
Title = Some "My Test Chapter"
|
Title = Some "My Test Chapter"
|
||||||
ImageUrl = Some "two-hours-in.jpg"
|
ImageUrl = Some "two-hours-in.jpg"
|
||||||
|
Url = Some "https://example.com/about"
|
||||||
IsHidden = Some true
|
IsHidden = Some true
|
||||||
EndTime = Some (Duration.FromSeconds 7313.788)
|
EndTime = Some (Duration.FromSeconds 7313.788)
|
||||||
Location = Some { Name = "Over Here"; Geo = Some "geo:23432"; Osm = Some "SF98fFSu-8" } }
|
Location = Some { Name = "Over Here"; Geo = "geo:23432"; Osm = Some "SF98fFSu-8" } }
|
||||||
Expect.equal chapter.StartTime "2:00:01.43" "Start time not filled/formatted properly"
|
Expect.equal chapter.StartTime "2:00:01.43" "Start time not filled/formatted properly"
|
||||||
Expect.equal chapter.Title "My Test Chapter" "Title not filled properly"
|
Expect.equal chapter.Title "My Test Chapter" "Title not filled properly"
|
||||||
Expect.equal chapter.ImageUrl "two-hours-in.jpg" "Image URL not filled properly"
|
Expect.equal chapter.ImageUrl "two-hours-in.jpg" "Image URL not filled properly"
|
||||||
|
Expect.equal chapter.Url "https://example.com/about" "URL not filled properly"
|
||||||
Expect.isTrue chapter.IsHidden "Is hidden flag not filled properly"
|
Expect.isTrue chapter.IsHidden "Is hidden flag not filled properly"
|
||||||
Expect.equal chapter.EndTime "2:01:53.78" "End time not filled/formatted properly"
|
Expect.equal chapter.EndTime "2:01:53.78" "End time not filled/formatted properly"
|
||||||
Expect.equal chapter.LocationName "Over Here" "Location name not filled properly"
|
Expect.equal chapter.LocationName "Over Here" "Location name not filled properly"
|
||||||
@ -1121,9 +1123,9 @@ let manageChaptersModelTests = testList "ManageChaptersModel.Create" [
|
|||||||
Expect.equal model.Id "test-post" "ID not filled properly"
|
Expect.equal model.Id "test-post" "ID not filled properly"
|
||||||
Expect.equal model.Title "Look at all these chapters" "Title not filled properly"
|
Expect.equal model.Title "Look at all these chapters" "Title not filled properly"
|
||||||
Expect.hasLength model.Chapters 3 "There should be three chapters"
|
Expect.hasLength model.Chapters 3 "There should be three chapters"
|
||||||
Expect.equal model.Chapters[0].StartTime "0:00:18" "First chapter not filled properly"
|
Expect.equal model.Chapters[0].StartTime (Duration.FromSeconds 18L) "First chapter not filled properly"
|
||||||
Expect.equal model.Chapters[1].StartTime "0:00:36" "Second chapter not filled properly"
|
Expect.equal model.Chapters[1].StartTime (Duration.FromSeconds 36L) "Second chapter not filled properly"
|
||||||
Expect.equal model.Chapters[2].StartTime "0:03:00.7" "Third chapter not filled properly"
|
Expect.equal model.Chapters[2].StartTime (Duration.FromSeconds 180.7) "Third chapter not filled properly"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -214,33 +214,23 @@ module RedirectRules =
|
|||||||
open Microsoft.AspNetCore.Http
|
open Microsoft.AspNetCore.Http
|
||||||
|
|
||||||
// GET /admin/settings/redirect-rules
|
// GET /admin/settings/redirect-rules
|
||||||
let all : HttpHandler = fun next ctx -> task {
|
let all : HttpHandler = fun next ctx ->
|
||||||
return!
|
adminPage "Redirect Rules" true (Views.Admin.redirectList ctx.WebLog.RedirectRules) next ctx
|
||||||
hashForPage "Redirect Rules"
|
|
||||||
|> withAntiCsrf ctx
|
|
||||||
|> addToHash "redirections" ctx.WebLog.RedirectRules
|
|
||||||
|> adminView "redirect-list" next ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET /admin/settings/redirect-rules/[index]
|
// GET /admin/settings/redirect-rules/[index]
|
||||||
let edit idx : HttpHandler = fun next ctx -> task {
|
let edit idx : HttpHandler = fun next ctx ->
|
||||||
if idx = -1 then
|
let titleAndModel =
|
||||||
return!
|
if idx = -1 then
|
||||||
hashForPage "Add Redirect Rule"
|
Some ("Add", Views.Admin.redirectEdit (EditRedirectRuleModel.FromRule -1 RedirectRule.Empty))
|
||||||
|> addToHash "model" (EditRedirectRuleModel.FromRule -1 RedirectRule.Empty)
|
|
||||||
|> withAntiCsrf ctx
|
|
||||||
|> adminBareView "redirect-edit" next ctx
|
|
||||||
else
|
|
||||||
let rules = ctx.WebLog.RedirectRules
|
|
||||||
if rules.Length < idx || idx < 0 then
|
|
||||||
return! Error.notFound next ctx
|
|
||||||
else
|
else
|
||||||
return!
|
let rules = ctx.WebLog.RedirectRules
|
||||||
hashForPage "Edit Redirect Rule"
|
if rules.Length < idx || idx < 0 then
|
||||||
|> addToHash "model" (EditRedirectRuleModel.FromRule idx (List.item idx rules))
|
None
|
||||||
|> withAntiCsrf ctx
|
else
|
||||||
|> adminBareView "redirect-edit" next ctx
|
Some ("Edit", (Views.Admin.redirectEdit (EditRedirectRuleModel.FromRule idx (List.item idx rules))))
|
||||||
}
|
match titleAndModel with
|
||||||
|
| Some (title, model) -> adminBarePage $"{title} Redirect Rule" true model next ctx
|
||||||
|
| None -> Error.notFound next ctx
|
||||||
|
|
||||||
/// Update the web log's redirect rules in the database, the request web log, and the web log cache
|
/// Update the web log's redirect rules in the database, the request web log, and the web log cache
|
||||||
let private updateRedirectRules (ctx: HttpContext) webLog = backgroundTask {
|
let private updateRedirectRules (ctx: HttpContext) webLog = backgroundTask {
|
||||||
@ -251,16 +241,15 @@ module RedirectRules =
|
|||||||
|
|
||||||
// POST /admin/settings/redirect-rules/[index]
|
// POST /admin/settings/redirect-rules/[index]
|
||||||
let save idx : HttpHandler = fun next ctx -> task {
|
let save idx : HttpHandler = fun next ctx -> task {
|
||||||
let! model = ctx.BindFormAsync<EditRedirectRuleModel>()
|
let! model = ctx.BindFormAsync<EditRedirectRuleModel>()
|
||||||
let isNew = idx = -1
|
let rule = model.ToRule()
|
||||||
let rules = ctx.WebLog.RedirectRules
|
let rules =
|
||||||
let rule = model.ToRule()
|
ctx.WebLog.RedirectRules
|
||||||
let newRules =
|
|> match idx with
|
||||||
match isNew with
|
| -1 when model.InsertAtTop -> List.insertAt 0 rule
|
||||||
| true when model.InsertAtTop -> List.insertAt 0 rule rules
|
| -1 -> List.insertAt ctx.WebLog.RedirectRules.Length rule
|
||||||
| true -> List.insertAt rules.Length rule rules
|
| _ -> List.removeAt idx >> List.insertAt idx rule
|
||||||
| false -> rules |> List.removeAt idx |> List.insertAt idx rule
|
do! updateRedirectRules ctx { ctx.WebLog with RedirectRules = rules }
|
||||||
do! updateRedirectRules ctx { ctx.WebLog with RedirectRules = newRules }
|
|
||||||
do! addMessage ctx { UserMessage.Success with Message = "Redirect rule saved successfully" }
|
do! addMessage ctx { UserMessage.Success with Message = "Redirect rule saved successfully" }
|
||||||
return! all next ctx
|
return! all next ctx
|
||||||
}
|
}
|
||||||
@ -287,7 +276,7 @@ module RedirectRules =
|
|||||||
return! all next ctx
|
return! all next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /admin/settings/redirect-rules/[index]/delete
|
// DELETE /admin/settings/redirect-rules/[index]
|
||||||
let delete idx : HttpHandler = fun next ctx -> task {
|
let delete idx : HttpHandler = fun next ctx -> task {
|
||||||
if idx < 0 || idx >= ctx.WebLog.RedirectRules.Length then
|
if idx < 0 || idx >= ctx.WebLog.RedirectRules.Length then
|
||||||
return! Error.notFound next ctx
|
return! Error.notFound next ctx
|
||||||
@ -302,25 +291,10 @@ module RedirectRules =
|
|||||||
/// ~~~ TAG MAPPINGS ~~~
|
/// ~~~ TAG MAPPINGS ~~~
|
||||||
module TagMapping =
|
module TagMapping =
|
||||||
|
|
||||||
open Microsoft.AspNetCore.Http
|
|
||||||
|
|
||||||
/// Add tag mappings to the given hash
|
|
||||||
let withTagMappings (ctx: HttpContext) hash = task {
|
|
||||||
let! mappings = ctx.Data.TagMap.FindByWebLog ctx.WebLog.Id
|
|
||||||
return
|
|
||||||
addToHash "mappings" mappings hash
|
|
||||||
|> addToHash "mapping_ids" (
|
|
||||||
mappings
|
|
||||||
|> List.map (fun it -> { Name = it.Tag; Value = string it.Id }))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET /admin/settings/tag-mappings
|
// GET /admin/settings/tag-mappings
|
||||||
let all : HttpHandler = fun next ctx -> task {
|
let all : HttpHandler = fun next ctx -> task {
|
||||||
let! hash =
|
let! mappings = ctx.Data.TagMap.FindByWebLog ctx.WebLog.Id
|
||||||
hashForPage ""
|
return! adminBarePage "Tag Mapping List" true (Views.Admin.tagMapList mappings) next ctx
|
||||||
|> withAntiCsrf ctx
|
|
||||||
|> withTagMappings ctx
|
|
||||||
return! adminBareView "tag-mapping-list-body" next ctx hash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /admin/settings/tag-mapping/{id}/edit
|
// GET /admin/settings/tag-mapping/{id}/edit
|
||||||
@ -332,10 +306,9 @@ module TagMapping =
|
|||||||
match! tagMap with
|
match! tagMap with
|
||||||
| Some tm ->
|
| Some tm ->
|
||||||
return!
|
return!
|
||||||
hashForPage (if isNew then "Add Tag Mapping" else $"Mapping for {tm.Tag} Tag")
|
adminBarePage
|
||||||
|> withAntiCsrf ctx
|
(if isNew then "Add Tag Mapping" else $"Mapping for {tm.Tag} Tag") true
|
||||||
|> addToHash ViewContext.Model (EditTagMapModel.FromMapping tm)
|
(Views.Admin.tagMapEdit (EditTagMapModel.FromMapping tm)) next ctx
|
||||||
|> adminBareView "tag-mapping-edit" next ctx
|
|
||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +327,7 @@ module TagMapping =
|
|||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /admin/settings/tag-mapping/{id}/delete
|
// DELETE /admin/settings/tag-mapping/{id}
|
||||||
let delete tagMapId : HttpHandler = fun next ctx -> task {
|
let delete tagMapId : HttpHandler = fun next ctx -> task {
|
||||||
match! ctx.Data.TagMap.Delete (TagMapId tagMapId) ctx.WebLog.Id with
|
match! ctx.Data.TagMap.Delete (TagMapId tagMapId) ctx.WebLog.Id with
|
||||||
| true -> do! addMessage ctx { UserMessage.Success with Message = "Tag mapping deleted successfully" }
|
| true -> do! addMessage ctx { UserMessage.Success with Message = "Tag mapping deleted successfully" }
|
||||||
@ -531,44 +504,36 @@ module WebLog =
|
|||||||
// GET /admin/settings
|
// GET /admin/settings
|
||||||
let settings : HttpHandler = fun next ctx -> task {
|
let settings : HttpHandler = fun next ctx -> task {
|
||||||
let data = ctx.Data
|
let data = ctx.Data
|
||||||
match! TemplateCache.get adminTheme "tag-mapping-list-body" ctx.Data with
|
let! allPages = data.Page.All ctx.WebLog.Id
|
||||||
| Ok tagMapTemplate ->
|
let! themes = data.Theme.All()
|
||||||
let! allPages = data.Page.All ctx.WebLog.Id
|
return!
|
||||||
let! themes = data.Theme.All()
|
hashForPage "Web Log Settings"
|
||||||
let! hash =
|
|> withAntiCsrf ctx
|
||||||
hashForPage "Web Log Settings"
|
|> addToHash ViewContext.Model (SettingsModel.FromWebLog ctx.WebLog)
|
||||||
|> withAntiCsrf ctx
|
|> addToHash "pages" (
|
||||||
|> addToHash ViewContext.Model (SettingsModel.FromWebLog ctx.WebLog)
|
seq {
|
||||||
|> addToHash "pages" (
|
KeyValuePair.Create("posts", "- First Page of Posts -")
|
||||||
seq {
|
yield! allPages
|
||||||
KeyValuePair.Create("posts", "- First Page of Posts -")
|
|> List.sortBy _.Title.ToLower()
|
||||||
yield! allPages
|
|> List.map (fun p -> KeyValuePair.Create(string p.Id, p.Title))
|
||||||
|> List.sortBy _.Title.ToLower()
|
}
|
||||||
|> List.map (fun p -> KeyValuePair.Create(string p.Id, p.Title))
|
|> Array.ofSeq)
|
||||||
}
|
|> addToHash "themes" (
|
||||||
|> Array.ofSeq)
|
themes
|
||||||
|> addToHash "themes" (
|
|> Seq.ofList
|
||||||
themes
|
|> Seq.map (fun it ->
|
||||||
|> Seq.ofList
|
KeyValuePair.Create(string it.Id, $"{it.Name} (v{it.Version})"))
|
||||||
|> Seq.map (fun it ->
|
|> Array.ofSeq)
|
||||||
KeyValuePair.Create(string it.Id, $"{it.Name} (v{it.Version})"))
|
|> addToHash "upload_values" [|
|
||||||
|> Array.ofSeq)
|
KeyValuePair.Create(string Database, "Database")
|
||||||
|> addToHash "upload_values" [|
|
KeyValuePair.Create(string Disk, "Disk")
|
||||||
KeyValuePair.Create(string Database, "Database")
|
|]
|
||||||
KeyValuePair.Create(string Disk, "Disk")
|
|> addToHash "rss_model" (EditRssModel.FromRssOptions ctx.WebLog.Rss)
|
||||||
|]
|
|> addToHash "custom_feeds" (
|
||||||
|> addToHash "rss_model" (EditRssModel.FromRssOptions ctx.WebLog.Rss)
|
ctx.WebLog.Rss.CustomFeeds
|
||||||
|> addToHash "custom_feeds" (
|
|> List.map (DisplayCustomFeed.FromFeed (CategoryCache.get ctx))
|
||||||
ctx.WebLog.Rss.CustomFeeds
|
|> Array.ofList)
|
||||||
|> List.map (DisplayCustomFeed.FromFeed (CategoryCache.get ctx))
|
|> adminView "settings" next ctx
|
||||||
|> Array.ofList)
|
|
||||||
|> addViewContext ctx
|
|
||||||
let! hash' = TagMapping.withTagMappings ctx hash
|
|
||||||
return!
|
|
||||||
hash'
|
|
||||||
|> addToHash "tag_mapping_list" (tagMapTemplate.Render hash')
|
|
||||||
|> adminView "settings" next ctx
|
|
||||||
| Error message -> return! Error.server message next ctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /admin/settings
|
// POST /admin/settings
|
||||||
|
@ -196,16 +196,12 @@ let router : HttpHandler = choose [
|
|||||||
routef "/%s/delete" Feed.deleteCustomFeed
|
routef "/%s/delete" Feed.deleteCustomFeed
|
||||||
])
|
])
|
||||||
subRoute "/redirect-rules" (choose [
|
subRoute "/redirect-rules" (choose [
|
||||||
routef "/%i" Admin.RedirectRules.save
|
routef "/%i" Admin.RedirectRules.save
|
||||||
routef "/%i/up" Admin.RedirectRules.moveUp
|
routef "/%i/up" Admin.RedirectRules.moveUp
|
||||||
routef "/%i/down" Admin.RedirectRules.moveDown
|
routef "/%i/down" Admin.RedirectRules.moveDown
|
||||||
routef "/%i/delete" Admin.RedirectRules.delete
|
|
||||||
])
|
])
|
||||||
subRoute "/tag-mapping" (choose [
|
route "/tag-mapping/save" >=> Admin.TagMapping.save
|
||||||
route "/save" >=> Admin.TagMapping.save
|
route "/user/save" >=> User.save
|
||||||
routef "/%s/delete" Admin.TagMapping.delete
|
|
||||||
])
|
|
||||||
route "/user/save" >=> User.save
|
|
||||||
])
|
])
|
||||||
subRoute "/theme" (choose [
|
subRoute "/theme" (choose [
|
||||||
route "/new" >=> Admin.Theme.save
|
route "/new" >=> Admin.Theme.save
|
||||||
@ -223,7 +219,9 @@ let router : HttpHandler = choose [
|
|||||||
routef "/%s/chapter/%i" Post.deleteChapter
|
routef "/%s/chapter/%i" Post.deleteChapter
|
||||||
])
|
])
|
||||||
subRoute "/settings" (requireAccess WebLogAdmin >=> choose [
|
subRoute "/settings" (requireAccess WebLogAdmin >=> choose [
|
||||||
routef "/user/%s" User.delete
|
routef "/user/%s" User.delete
|
||||||
|
routef "/redirect-rules/%i" Admin.RedirectRules.delete
|
||||||
|
routef "/tag-mapping/%s" Admin.TagMapping.delete
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
module MyWebLog.Views.Admin
|
module MyWebLog.Views.Admin
|
||||||
|
|
||||||
|
open Giraffe.Htmx.Common
|
||||||
open Giraffe.ViewEngine
|
open Giraffe.ViewEngine
|
||||||
|
open Giraffe.ViewEngine.Accessibility
|
||||||
|
open Giraffe.ViewEngine.Htmx
|
||||||
|
open MyWebLog
|
||||||
open MyWebLog.ViewModels
|
open MyWebLog.ViewModels
|
||||||
|
|
||||||
/// The main dashboard
|
/// The main dashboard
|
||||||
@ -75,3 +79,217 @@ let dashboard (model: DashboardModel) app = [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
/// Redirect Rule edit form
|
||||||
|
let redirectEdit (model: EditRedirectRuleModel) app = [
|
||||||
|
let url = relUrl app $"admin/settings/redirect-rules/{model.RuleId}"
|
||||||
|
h3 [] [ raw (if model.RuleId < 0 then "Add" else "Edit"); raw " Redirect Rule" ]
|
||||||
|
form [ _action url; _hxPost url; _hxTarget "body"; _method "post"; _class "container" ] [
|
||||||
|
antiCsrf app
|
||||||
|
input [ _type "hidden"; _name "RuleId"; _value (string model.RuleId) ]
|
||||||
|
div [ _class "row" ] [
|
||||||
|
div [ _class "col-12 col-lg-5 mb-3" ] [
|
||||||
|
div [ _class "form-floating" ] [
|
||||||
|
input [ _type "text"; _name "From"; _id "from"; _class "form-control"
|
||||||
|
_placeholder "From local URL/pattern"; _autofocus; _required; _value model.From ]
|
||||||
|
label [ _for "from" ] [ raw "From" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "col-12 col-lg-5 mb-3" ] [
|
||||||
|
div [ _class "form-floating" ] [
|
||||||
|
input [ _type "text"; _name "To"; _id "to"; _class "form-control"; _placeholder "To URL/pattern"
|
||||||
|
_required; _value model.To ]
|
||||||
|
label [ _for "to" ] [ raw "To" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "col-12 col-lg-2 mb-3" ] [
|
||||||
|
div [ _class "form-check form-switch" ] [
|
||||||
|
input [ _type "checkbox"; _name "IsRegex"; _id "isRegex"; _class "form-check-input"; _value "true"
|
||||||
|
if model.IsRegex then _checked ]
|
||||||
|
label [ _for "isRegex" ] [ raw "Use RegEx" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
if model.RuleId < 0 then
|
||||||
|
div [ _class "row mb-3" ] [
|
||||||
|
div [ _class "col-12 text-center" ] [
|
||||||
|
label [ _class "me-1" ] [ raw "Add Rule" ]
|
||||||
|
div [ _class "btn-group btn-group-sm"; _roleGroup; _ariaLabel "New rule placement button group" ] [
|
||||||
|
input [ _type "radio"; _name "InsertAtTop"; _id "at_top"; _class "btn-check"; _value "true" ]
|
||||||
|
label [ _class "btn btn-sm btn-outline-secondary"; _for "at_top" ] [ raw "Top" ]
|
||||||
|
input [ _type "radio"; _name "InsertAtTop"; _id "at_bot"; _class "btn-check"; _value "false"
|
||||||
|
_checked ]
|
||||||
|
label [ _class "btn btn-sm btn-outline-secondary"; _for "at_bot" ] [ raw "Bottom" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "row mb-3" ] [
|
||||||
|
div [ _class "col text-center" ] [
|
||||||
|
button [ _type "submit"; _class "btn btn-sm btn-primary" ] [ raw "Save Changes" ]
|
||||||
|
a [ _href (relUrl app "admin/settings/redirect-rules"); _class "btn btn-sm btn-secondary ms-3" ] [
|
||||||
|
raw "Cancel"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
/// The list of current redirect rules
|
||||||
|
let redirectList (model: RedirectRule list) app = [
|
||||||
|
// Generate the detail for a redirect rule
|
||||||
|
let ruleDetail idx (rule: RedirectRule) =
|
||||||
|
let ruleId = $"rule_{idx}"
|
||||||
|
div [ _class "row mwl-table-detail"; _id ruleId ] [
|
||||||
|
div [ _class "col-5 no-wrap" ] [
|
||||||
|
txt rule.From; br []
|
||||||
|
small [] [
|
||||||
|
let ruleUrl = relUrl app $"admin/settings/redirect-rules/{idx}"
|
||||||
|
a [ _href ruleUrl; _hxTarget $"#{ruleId}"; _hxSwap $"{HxSwap.InnerHtml} show:#{ruleId}:top" ] [
|
||||||
|
raw "Edit"
|
||||||
|
]
|
||||||
|
if idx > 0 then
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href $"{ruleUrl}/up"; _hxPost $"{ruleUrl}/up" ] [ raw "Move Up" ]
|
||||||
|
if idx <> model.Length - 1 then
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href $"{ruleUrl}/down"; _hxPost $"{ruleUrl}/down" ] [ raw "Move Down" ]
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _class "text-danger"; _href ruleUrl; _hxDelete ruleUrl
|
||||||
|
_hxConfirm "Are you sure you want to delete this redirect rule?" ] [
|
||||||
|
raw "Delete"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "col-5" ] [ txt rule.To ]
|
||||||
|
div [ _class "col-2 text-center" ] [ yesOrNo rule.IsRegex ]
|
||||||
|
]
|
||||||
|
h2 [ _class "my-3" ] [ raw app.PageTitle ]
|
||||||
|
article [] [
|
||||||
|
p [ _class "mb-3" ] [
|
||||||
|
a [ _href (relUrl app "admin/settings") ] [ raw "« Back to Settings" ]
|
||||||
|
]
|
||||||
|
div [ _class "container" ] [
|
||||||
|
div [ _class "row" ] [
|
||||||
|
div [ _class "col" ] [
|
||||||
|
a [ _href (relUrl app "admin/settings/redirect-rules/-1"); _class "btn btn-primary btn-sm mb-3"
|
||||||
|
_hxTarget "#rule_new" ] [
|
||||||
|
raw "Add Redirect Rule"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "row" ] [
|
||||||
|
div [ _class "col" ] [
|
||||||
|
if List.isEmpty model then
|
||||||
|
div [ _id "rule_new" ] [
|
||||||
|
p [ _class "text-muted text-center fst-italic" ] [
|
||||||
|
raw "This web log has no redirect rules defined"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
else
|
||||||
|
div [ _class "container g-0" ] [
|
||||||
|
div [ _class "row mwl-table-heading" ] [
|
||||||
|
div [ _class "col-5" ] [ raw "From" ]
|
||||||
|
div [ _class "col-5" ] [ raw "To" ]
|
||||||
|
div [ _class "col-2 text-center" ] [ raw "RegEx?" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "row mwl-table-detail"; _id "rule_new" ] []
|
||||||
|
form [ _method "post"; _class "container g-0"; _hxTarget "body" ] [
|
||||||
|
antiCsrf app; yield! List.mapi ruleDetail model
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
p [ _class "mt-3 text-muted fst-italic text-center" ] [
|
||||||
|
raw "This is an advanced feature; please "
|
||||||
|
a [ _href "https://bitbadger.solutions/open-source/myweblog/advanced.html#redirect-rules"
|
||||||
|
_target "_blank" ] [
|
||||||
|
raw "read and understand the documentation on this feature"
|
||||||
|
]
|
||||||
|
raw " before adding rules."
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
/// Edit a tag mapping
|
||||||
|
let tagMapEdit (model: EditTagMapModel) app = [
|
||||||
|
h5 [ _class "my-3" ] [ txt app.PageTitle ]
|
||||||
|
form [ _hxPost (relUrl app "admin/settings/tag-mapping/save"); _method "post"; _class "container"
|
||||||
|
_hxTarget "#tagList"; _hxSwap $"{HxSwap.OuterHtml} show:window:top" ] [
|
||||||
|
antiCsrf app
|
||||||
|
input [ _type "hidden"; _name "Id"; _value model.Id ]
|
||||||
|
div [ _class "row mb-3" ] [
|
||||||
|
div [ _class "col-6 col-lg-4 offset-lg-2" ] [
|
||||||
|
div [ _class "form-floating" ] [
|
||||||
|
input [ _type "text"; _name "Tag"; _id "tag"; _class "form-control"; _placeholder "Tag"; _autofocus
|
||||||
|
_required; _value model.Tag ]
|
||||||
|
label [ _for "tag" ] [ raw "Tag" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "col-6 col-lg-4" ] [
|
||||||
|
div [ _class "form-floating" ] [
|
||||||
|
input [ _type "text"; _name "UrlValue"; _id "urlValue"; _class "form-control"
|
||||||
|
_placeholder "URL Value"; _required; _value model.UrlValue ]
|
||||||
|
label [ _for "urlValue" ] [ raw "URL Value" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "row mb-3" ] [
|
||||||
|
div [ _class "col text-center" ] [
|
||||||
|
button [ _type "submit"; _class "btn btn-sm btn-primary" ] [ raw "Save Changes" ]; raw " "
|
||||||
|
a [ _href (relUrl app "admin/settings/tag-mappings"); _class "btn btn-sm btn-secondary ms-3" ] [
|
||||||
|
raw "Cancel"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
/// Display a list of the web log's current tag mappings
|
||||||
|
let tagMapList (model: TagMap list) app =
|
||||||
|
let tagMapDetail (map: TagMap) =
|
||||||
|
let url = relUrl app $"admin/settings/tag-mapping/{map.Id}"
|
||||||
|
div [ _class "row mwl-table-detail"; _id $"tag_{map.Id}" ] [
|
||||||
|
div [ _class "col no-wrap" ] [
|
||||||
|
txt map.Tag; br []
|
||||||
|
small [] [
|
||||||
|
a [ _href $"{url}/edit"; _hxTarget $"#tag_{map.Id}"
|
||||||
|
_hxSwap $"{HxSwap.InnerHtml} show:#tag_{map.Id}:top" ] [
|
||||||
|
raw "Edit"
|
||||||
|
]
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href url; _hxDelete url; _class "text-danger"
|
||||||
|
_hxConfirm $"Are you sure you want to delete the mapping for “{map.Tag}”? This action cannot be undone." ] [
|
||||||
|
raw "Delete"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "col" ] [ txt map.UrlValue ]
|
||||||
|
]
|
||||||
|
div [ _id "tagList"; _class "container" ] [
|
||||||
|
div [ _class "row" ] [
|
||||||
|
div [ _class "col" ] [
|
||||||
|
if List.isEmpty model then
|
||||||
|
div [ _id "tag_new" ] [
|
||||||
|
p [ _class "text-muted text-center fst-italic" ] [ raw "This web log has no tag mappings" ]
|
||||||
|
]
|
||||||
|
else
|
||||||
|
div [ _class "container g-0" ] [
|
||||||
|
div [ _class "row mwl-table-heading" ] [
|
||||||
|
div [ _class "col" ] [ raw "Tag" ]
|
||||||
|
div [ _class "col" ] [ raw "URL Value" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
form [ _method "post"; _class "container g-0"; _hxTarget "#tagList"; _hxSwap HxSwap.OuterHtml ] [
|
||||||
|
antiCsrf app
|
||||||
|
div [ _class "row mwl-table-detail"; _id "tag_new" ] []
|
||||||
|
yield! List.map tagMapDetail model
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|> List.singleton
|
||||||
|
@ -98,6 +98,10 @@ let shortTime app (instant: Instant) =
|
|||||||
|> Option.defaultValue "--"
|
|> Option.defaultValue "--"
|
||||||
|> txt
|
|> txt
|
||||||
|
|
||||||
|
/// Display "Yes" or "No" based on the state of a boolean value
|
||||||
|
let yesOrNo value =
|
||||||
|
raw (if value then "Yes" else "No")
|
||||||
|
|
||||||
/// Functions for generating content in varying layouts
|
/// Functions for generating content in varying layouts
|
||||||
module Layout =
|
module Layout =
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module MyWebLog.Views.Post
|
module MyWebLog.Views.Post
|
||||||
|
|
||||||
|
open Giraffe.Htmx.Common
|
||||||
open Giraffe.ViewEngine
|
open Giraffe.ViewEngine
|
||||||
open Giraffe.ViewEngine.Htmx
|
open Giraffe.ViewEngine.Htmx
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
@ -147,7 +148,7 @@ let chapterEdit (model: EditChapterModel) app = [
|
|||||||
|
|
||||||
/// Display a list of chapters
|
/// Display a list of chapters
|
||||||
let chapterList withNew (model: ManageChaptersModel) app =
|
let chapterList withNew (model: ManageChaptersModel) app =
|
||||||
form [ _method "post"; _id "chapter_list"; _class "container mb-3"; _hxTarget "this"; _hxSwap "outerHTML" ] [
|
form [ _method "post"; _id "chapter_list"; _class "container mb-3"; _hxTarget "this"; _hxSwap HxSwap.OuterHtml ] [
|
||||||
antiCsrf app
|
antiCsrf app
|
||||||
input [ _type "hidden"; _name "Id"; _value model.Id ]
|
input [ _type "hidden"; _name "Id"; _value model.Id ]
|
||||||
div [ _class "row mwl-table-heading" ] [
|
div [ _class "row mwl-table-heading" ] [
|
||||||
@ -170,7 +171,7 @@ let chapterList withNew (model: ManageChaptersModel) app =
|
|||||||
else
|
else
|
||||||
let chapterUrl = relUrl app $"admin/post/{model.Id}/chapter/{idx}"
|
let chapterUrl = relUrl app $"admin/post/{model.Id}/chapter/{idx}"
|
||||||
a [ _href chapterUrl; _hxGet chapterUrl; _hxTarget $"#chapter{idx}"
|
a [ _href chapterUrl; _hxGet chapterUrl; _hxTarget $"#chapter{idx}"
|
||||||
_hxSwap $"innerHTML show:#chapter{idx}:top" ] [
|
_hxSwap $"{HxSwap.InnerHtml} show:#chapter{idx}:top" ] [
|
||||||
raw "Edit"
|
raw "Edit"
|
||||||
]
|
]
|
||||||
span [ _class "text-muted" ] [ raw " • " ]
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
@ -179,12 +180,8 @@ let chapterList withNew (model: ManageChaptersModel) app =
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
div [ _class "col-3 col-md-2 col-lg-1 text-center" ] [
|
div [ _class "col-3 col-md-2 col-lg-1 text-center" ] [ yesOrNo (Option.isSome chapter.ImageUrl) ]
|
||||||
raw (match chapter.ImageUrl with Some _ -> "Y" | None -> "N")
|
div [ _class "col-3 col-md-2 col-lg-1 text-center" ] [ yesOrNo (Option.isSome chapter.Location) ]
|
||||||
]
|
|
||||||
div [ _class "col-3 col-md-2 col-lg-1 text-center" ] [
|
|
||||||
raw (match chapter.Location with Some _ -> "Y" | None -> "N")
|
|
||||||
]
|
|
||||||
])
|
])
|
||||||
div [ _class "row pb-3"; _id "chapter-1" ] [
|
div [ _class "row pb-3"; _id "chapter-1" ] [
|
||||||
let newLink = relUrl app $"admin/post/{model.Id}/chapter/-1"
|
let newLink = relUrl app $"admin/post/{model.Id}/chapter/-1"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module MyWebLog.Views.User
|
module MyWebLog.Views.User
|
||||||
|
|
||||||
|
open Giraffe.Htmx.Common
|
||||||
open Giraffe.ViewEngine
|
open Giraffe.ViewEngine
|
||||||
open Giraffe.ViewEngine.Htmx
|
open Giraffe.ViewEngine.Htmx
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
@ -12,7 +13,7 @@ let edit (model: EditUserModel) app =
|
|||||||
div [ _class "col-12" ] [
|
div [ _class "col-12" ] [
|
||||||
h5 [ _class "my-3" ] [ txt app.PageTitle ]
|
h5 [ _class "my-3" ] [ txt app.PageTitle ]
|
||||||
form [ _hxPost (relUrl app "admin/settings/user/save"); _method "post"; _class "container"
|
form [ _hxPost (relUrl app "admin/settings/user/save"); _method "post"; _class "container"
|
||||||
_hxTarget "#userList"; _hxSwap "outerHTML show:window:top" ] [
|
_hxTarget "#userList"; _hxSwap $"{HxSwap.OuterHtml} show:window:top" ] [
|
||||||
antiCsrf app
|
antiCsrf app
|
||||||
input [ _type "hidden"; _name "Id"; _value model.Id ]
|
input [ _type "hidden"; _name "Id"; _value model.Id ]
|
||||||
div [ _class "row" ] [
|
div [ _class "row" ] [
|
||||||
@ -167,7 +168,8 @@ let userList (model: WebLogUser list) app =
|
|||||||
div [ _class "container g-0" ] [
|
div [ _class "container g-0" ] [
|
||||||
div [ _class "row mwl-table-detail"; _id "user_new" ] []
|
div [ _class "row mwl-table-detail"; _id "user_new" ] []
|
||||||
]
|
]
|
||||||
form [ _method "post"; _class "container g-0"; _hxTarget "this"; _hxSwap "outerHTML show:window:top" ] [
|
form [ _method "post"; _class "container g-0"; _hxTarget "this"
|
||||||
|
_hxSwap $"{HxSwap.OuterHtml} show:window:top" ] [
|
||||||
antiCsrf app
|
antiCsrf app
|
||||||
for user in model do
|
for user in model do
|
||||||
div [ _class "row mwl-table-detail"; _id $"user_{user.Id}" ] [
|
div [ _class "row mwl-table-detail"; _id $"user_{user.Id}" ] [
|
||||||
@ -183,7 +185,7 @@ let userList (model: WebLogUser list) app =
|
|||||||
let userUrl = relUrl app $"admin/settings/user/{user.Id}"
|
let userUrl = relUrl app $"admin/settings/user/{user.Id}"
|
||||||
small [] [
|
small [] [
|
||||||
a [ _href $"{userUrl}/edit"; _hxTarget $"#user_{user.Id}"
|
a [ _href $"{userUrl}/edit"; _hxTarget $"#user_{user.Id}"
|
||||||
_hxSwap $"innerHTML show:#user_{user.Id}:top" ] [
|
_hxSwap $"{HxSwap.InnerHtml} show:#user_{user.Id}:top" ] [
|
||||||
raw "Edit"
|
raw "Edit"
|
||||||
]
|
]
|
||||||
if app.UserId.Value <> user.Id then
|
if app.UserId.Value <> user.Id then
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"Generator": "myWebLog 2.0",
|
|
||||||
"Generator": "myWebLog 2.1",
|
"Generator": "myWebLog 2.1",
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
<h3>{% if model.rule_id < 0 %}Add{% else %}Edit{% endif %} Redirect Rule</h3>
|
|
||||||
{%- assign post_url = "admin/settings/redirect-rules/" | append: model.rule_id | relative_link -%}
|
|
||||||
<form action="{{ post_url }}" hx-post="{{ post_url }}" hx-target=body method=post class=container>
|
|
||||||
<input type=hidden name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
|
||||||
<input type=hidden name=RuleId value="{{ model.rule_id }}">
|
|
||||||
<div class=row>
|
|
||||||
<div class="col-12 col-lg-5 mb-3">
|
|
||||||
<div class=form-floating>
|
|
||||||
<input type=text name=From id=from class=form-control placeholder="From local URL/pattern" autofocus required
|
|
||||||
value="{{ model.from | escape }}">
|
|
||||||
<label for=from>From</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-5 mb-3">
|
|
||||||
<div class=form-floating>
|
|
||||||
<input type=text name=To id=to class=form-control placeholder="To URL/pattern" required
|
|
||||||
value="{{ model.to | escape }}">
|
|
||||||
<label for=to>To</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-lg-2 mb-3">
|
|
||||||
<div class="form-check form-switch">
|
|
||||||
<input type=checkbox name=IsRegex id=isRegex class=form-check-input value=true
|
|
||||||
{%- if model.is_regex %} checked{% endif %}>
|
|
||||||
<label for=isRegex>Use RegEx</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% if model.rule_id < 0 %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-12 text-center">
|
|
||||||
<label>Add Rule</label>
|
|
||||||
<div class="btn-group btn-group-sm" role=group aria-label="New rule placement button group">
|
|
||||||
<input type=radio name=InsertAtTop id=insert_top class=btn-check value=true>
|
|
||||||
<label class="btn btn-sm btn-outline-secondary" for=insert_top>Top</label>
|
|
||||||
<input type=radio name=InsertAtTop id=insert_bottom class=btn-check value=false checked>
|
|
||||||
<label class="btn btn-sm btn-outline-secondary" for=insert_bottom>Bottom</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col text-center">
|
|
||||||
<button type=submit class="btn btn-sm btn-primary">Save Changes</button>
|
|
||||||
<a href="{{ "admin/settings/redirect-rules" | relative_link }}" class="btn btn-sm btn-secondary ms-3">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
@ -1,75 +0,0 @@
|
|||||||
<h2 class=my-3>{{ page_title }}</h2>
|
|
||||||
<article>
|
|
||||||
<p class=mb-3>
|
|
||||||
<a href="{{ "admin/settings" | relative_link }}">« Back to Settings</a>
|
|
||||||
</p>
|
|
||||||
<div class=container>
|
|
||||||
<div class=row>
|
|
||||||
<div class=col>
|
|
||||||
<a href="{{ "admin/settings/redirect-rules/-1" | relative_link }}" class="btn btn-primary btn-sm mb-3"
|
|
||||||
hx-target=#redir_new>
|
|
||||||
Add Redirect Rule
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class=row>
|
|
||||||
<div class=col>
|
|
||||||
{%- assign redir_count = redirections | size -%}
|
|
||||||
{% if redir_count > 0 -%}
|
|
||||||
<div class=container>
|
|
||||||
<div class="row mwl-table-heading">
|
|
||||||
<div class=col-5>From</div>
|
|
||||||
<div class=col-5>To</div>
|
|
||||||
<div class="col-2 text-center">RegEx?</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mwl-table-detail" id=redir_new></div>
|
|
||||||
<form method=post class=container hx-target=body>
|
|
||||||
<input type=hidden name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
|
||||||
{% for redir in redirections -%}
|
|
||||||
{%- assign redir_id = "redir_" | append: forloop.index0 -%}
|
|
||||||
<div class="row mwl-table-detail" id="{{ redir_id }}">
|
|
||||||
<div class="col-5 no-wrap">
|
|
||||||
{{ redir.from }}<br>
|
|
||||||
<small>
|
|
||||||
{%- assign redir_url = "admin/settings/redirect-rules/" | append: forloop.index0 -%}
|
|
||||||
<a href="{{ redir_url | relative_link }}" hx-target="#{{ redir_id }}"
|
|
||||||
hx-swap="innerHTML show:#{{ redir_id }}:top">
|
|
||||||
Edit
|
|
||||||
</a>
|
|
||||||
{% unless forloop.first %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
{%- assign move_up = redir_url | append: "/up" | relative_link -%}
|
|
||||||
<a href="{{ move_up }}" hx-post="{{ move_up }}">Move Up</a>
|
|
||||||
{% endunless %}
|
|
||||||
{% unless forloop.last %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
{%- assign move_down = redir_url | append: "/down" | relative_link -%}
|
|
||||||
<a href="{{ move_down }}" hx-post="{{ move_down }}">Move Down</a>
|
|
||||||
{% endunless %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
{%- assign del_url = redir_url | append: "/delete" | relative_link -%}
|
|
||||||
<a href="{{ del_url }}" hx-post="{{ del_url }}" class=text-danger
|
|
||||||
hx-confirm="Are you sure you want to delete this redirect rule?">
|
|
||||||
Delete
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
<div class=col-5>{{ redir.to }}</div>
|
|
||||||
<div class="col-2 text-center">{% if redir.is_regex %}Yes{% else %}No{% endif %}</div>
|
|
||||||
</div>
|
|
||||||
{%- endfor %}
|
|
||||||
</form>
|
|
||||||
{%- else -%}
|
|
||||||
<div id=redir_new>
|
|
||||||
<p class="text-muted text-center fst-italic">This web log has no redirect rules defined
|
|
||||||
</div>
|
|
||||||
{%- endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="mt-3 text-muted fst-italic text-center">
|
|
||||||
This is an advanced feature; please
|
|
||||||
<a href=https://bitbadger.solutions/open-source/myweblog/advanced.html#redirect-rules
|
|
||||||
target=_blank>read and understand the documentation on this feature</a> before adding rules.
|
|
||||||
</article>
|
|
@ -244,6 +244,6 @@
|
|||||||
hx-target=#tag_new>
|
hx-target=#tag_new>
|
||||||
Add a New Tag Mapping
|
Add a New Tag Mapping
|
||||||
</a>
|
</a>
|
||||||
{{ tag_mapping_list }}
|
<span hx-get="{{ "admin/settings/tag-mappings" | relative_link }}" hx-trigger="load" hx-swap="outerHTML"></span>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</article>
|
</article>
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
<h5 class=my-3>{{ page_title }}</h5>
|
|
||||||
<form hx-post="{{ "admin/settings/tag-mapping/save" | relative_link }}" method=post class=container hx-target=#tagList
|
|
||||||
hx-swap="outerHTML show:window:top">
|
|
||||||
<input type=hidden name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
|
||||||
<input type=hidden name=Id value="{{ model.id }}">
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-6 col-lg-4 offset-lg-2">
|
|
||||||
<div class=form-floating>
|
|
||||||
<input type=text name=Tag id=tag class=form-control placeholder=Tag autofocus required value="{{ model.tag }}">
|
|
||||||
<label for=tag>Tag</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 col-lg-4">
|
|
||||||
<div class=form-floating>
|
|
||||||
<input type=text name=UrlValue id=urlValue class=form-control placeholder="URL Value" required
|
|
||||||
value="{{ model.url_value }}">
|
|
||||||
<label for=urlValue>URL Value</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col text-center">
|
|
||||||
<button type=submit class="btn btn-sm btn-primary">Save Changes</button>
|
|
||||||
<a href="{{ "admin/settings/tag-mappings" | relative_link }}" class="btn btn-sm btn-secondary ms-3">Cancel</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
@ -1,43 +0,0 @@
|
|||||||
<div id=tagList class=container>
|
|
||||||
<div class=row>
|
|
||||||
<div class=col>
|
|
||||||
{%- assign map_count = mappings | size -%}
|
|
||||||
{% if map_count > 0 -%}
|
|
||||||
<div class=container>
|
|
||||||
<div class="row mwl-table-heading">
|
|
||||||
<div class=col>Tag</div>
|
|
||||||
<div class=col>URL Value</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<form method=post class=container hx-target=#tagList hx-swap=outerHTML>
|
|
||||||
<input type=hidden name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
|
||||||
<div class="row mwl-table-detail" id=tag_new></div>
|
|
||||||
{% for map in mappings -%}
|
|
||||||
{%- assign map_id = mapping_ids | value: map.tag -%}
|
|
||||||
<div class="row mwl-table-detail" id="tag_{{ map_id }}">
|
|
||||||
<div class="col no-wrap">
|
|
||||||
{{ map.tag }}<br>
|
|
||||||
<small>
|
|
||||||
{%- assign map_url = "admin/settings/tag-mapping/" | append: map_id -%}
|
|
||||||
<a href="{{ map_url | append: "/edit" | relative_link }}" hx-target="#tag_{{ map_id }}"
|
|
||||||
hx-swap="innerHTML show:#tag_{{ map_id }}:top">
|
|
||||||
Edit
|
|
||||||
</a>
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
{%- assign map_del_link = map_url | append: "/delete" | relative_link -%}
|
|
||||||
<a href="{{ map_del_link }}" hx-post="{{ map_del_link }}" class=text-danger
|
|
||||||
hx-confirm="Are you sure you want to delete the mapping for “{{ map.tag }}”? This action cannot be undone.">
|
|
||||||
Delete
|
|
||||||
</a>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
<div class=col>{{ map.url_value }}</div>
|
|
||||||
</div>
|
|
||||||
{%- endfor %}
|
|
||||||
</form>
|
|
||||||
{%- else -%}
|
|
||||||
<div id=tag_new><p class="text-muted text-center fst-italic">This web log has no tag mappings</div>
|
|
||||||
{%- endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
Loading…
Reference in New Issue
Block a user