Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe9d8e71f4 | |||
| 0c3bf0701d | |||
| 0bc777c6f1 | |||
| 2055bba5f0 | |||
| a2a1f9c06d | |||
| 79280135a1 | |||
| 4422f3840e | |||
| ffcf7c0438 | |||
| a910aac946 | |||
| eed41aebbb | |||
| 037be4d7e8 | |||
| 6cf327226d |
@@ -21,6 +21,7 @@ type BookmarkManager struct {
|
|||||||
type SearchOptions struct {
|
type SearchOptions struct {
|
||||||
Query string
|
Query string
|
||||||
Tags []string
|
Tags []string
|
||||||
|
Sort string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBookmarkManager(db *DB) *BookmarkManager {
|
func NewBookmarkManager(db *DB) *BookmarkManager {
|
||||||
@@ -138,10 +139,32 @@ func (m *BookmarkManager) Search(opts SearchOptions) ([]entity.Bookmark, error)
|
|||||||
bhQuery = bolthold.Query(*bhQuery.And("Tags").ContainsAll(bolthold.Slice(opts.Tags)...))
|
bhQuery = bolthold.Query(*bhQuery.And("Tags").ContainsAll(bolthold.Slice(opts.Tags)...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reverse := false
|
||||||
|
sortOrder := opts.Sort
|
||||||
|
if sortOrder != "" && sortOrder[0] == '-' {
|
||||||
|
reverse = true
|
||||||
|
sortOrder = sortOrder[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if sortOrder == "title" {
|
||||||
|
bhQuery.SortBy("Info.Title")
|
||||||
|
} else if sortOrder == "created" {
|
||||||
|
bhQuery.SortBy("TimestampCreated")
|
||||||
|
} else if sortOrder == "scraped" {
|
||||||
|
bhQuery.SortBy("TimestampLastScraped")
|
||||||
|
} else {
|
||||||
|
bhQuery.SortBy("ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
if reverse {
|
||||||
|
bhQuery = *bhQuery.Reverse()
|
||||||
|
}
|
||||||
|
|
||||||
out := []entity.Bookmark{}
|
out := []entity.Bookmark{}
|
||||||
err := m.db.store.ForEach(&bhQuery,
|
err := m.db.store.ForEach(&bhQuery,
|
||||||
func(bm *entity.Bookmark) error {
|
func(bm *entity.Bookmark) error {
|
||||||
out = append(out, *bm)
|
out = append(out, *bm)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Tag = "v0.0.21"
|
const Tag = "v0.0.26"
|
||||||
|
|
||||||
var versionInfo struct {
|
var versionInfo struct {
|
||||||
Local struct {
|
Local struct {
|
||||||
@@ -55,7 +55,7 @@ func UpdateVersionInfo() {
|
|||||||
|
|
||||||
rels, _, err := client.Repositories.ListReleases(context.Background(), "tardisx", "linkwallet", nil)
|
rels, _, err := client.Repositories.ListReleases(context.Background(), "tardisx", "linkwallet", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
if len(rels) == 0 {
|
if len(rels) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<div class="large-8 medium-8 cell" id="add-url-form" >
|
<div class="large-8 medium-8 cell" id="add-url-form" >
|
||||||
<div>
|
<div>
|
||||||
<h5 style="display:inline-block;">Add a new URL</h5>
|
<h5 style="display:inline-block;">Add a new URL</h5>
|
||||||
<p style="display:inline-block;">[<a hx-get="/bulk_add" hx-target="#add-url-form" href="#">bulk add</a>]</h5>
|
<div style="display:inline-block;">[<a hx-get="/bulk_add" hx-swap="outerHTML" hx-target="#add-url-form" href="#">bulk add</a>]</div></h5>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onsubmit="return false">
|
<form onsubmit="return false">
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
<div class="large-8 medium-8 cell" id="add-url-form" >
|
<div class="large-8 medium-8 cell" id="add-url-form" >
|
||||||
<div>
|
<div>
|
||||||
<h5 style="display:inline-block;">Add bulk URLs</h5>
|
<h5 style="display:inline-block;">Add bulk URLs</h5>
|
||||||
<p style="display:inline-block;">[<a hx-get="/single_add" hx-target="#add-url-form" href="#">single add</a>]</h5>
|
<p style="display:inline-block;">[<a hx-get="/single_add" hx-swap="outerHTML" hx-target="#add-url-form" href="#">single add</a>]</h5>
|
||||||
</div> <form onsubmit="return false">
|
</div>
|
||||||
|
<form onsubmit="return false">
|
||||||
<div class="grid-x grid-padding-x">
|
<div class="grid-x grid-padding-x">
|
||||||
<div class="large-12 cell">
|
<div class="large-12 cell">
|
||||||
<label>Paste URL's, one per line</label>
|
<label>Paste URL's, one per line</label>
|
||||||
<textarea type="text" name="urls" rows="10"
|
<textarea type="text" name="urls" rows="10"></textarea>
|
||||||
></textarea>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -13,8 +13,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ template "tags_widget.html" . }}
|
{{ template "tags_widget.html" . }}
|
||||||
</form>
|
|
||||||
{{ template "manage_results.html" . }}
|
{{ template "manage_results.html" . }}
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
<table id="manage-results">
|
<table id="manage-results">
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>title/url</th>
|
{{ template "manage_results_column_header.html" .column.title }}
|
||||||
<th>tags</th>
|
<th>tags</th>
|
||||||
<th class="show-for-large">created</th>
|
{{ template "manage_results_column_header.html" .column.created }}
|
||||||
<th class="show-for-large">scraped</th>
|
{{ template "manage_results_column_header.html" .column.scraped }}
|
||||||
</tr>
|
</tr>
|
||||||
{{ range .bookmarks }}
|
{{ range .bookmarks }}
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
3
web/templates/manage_results_column_header.html
Normal file
3
web/templates/manage_results_column_header.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
<th class="{{ .Class }}" hx-post="/manage/results?sort={{ .URLString }}" hx-target="#manage-results">{{ .Name }} {{ .TitleArrow }}
|
||||||
|
</th>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="small-9 medium-10 large-5 cell"
|
<div class="small-9 medium-10 large-5 cell"
|
||||||
hx-post="/tags"
|
hx-post="/tags"
|
||||||
hx-target="#label-widget"
|
hx-target="#label-widget"
|
||||||
hx-trigger="change">
|
hx-trigger="change queue:first">
|
||||||
<label for="tag-entry"
|
<label for="tag-entry"
|
||||||
class="">Tags</label>
|
class="">Tags</label>
|
||||||
|
|
||||||
|
|||||||
62
web/web.go
62
web/web.go
@@ -42,6 +42,29 @@ type Server struct {
|
|||||||
bmm *db.BookmarkManager
|
bmm *db.BookmarkManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ColumnInfo struct {
|
||||||
|
Name string
|
||||||
|
Param string
|
||||||
|
Sorted string
|
||||||
|
Class string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ColumnInfo) URLString() string {
|
||||||
|
if c.Sorted == "asc" {
|
||||||
|
return "-" + c.Param
|
||||||
|
}
|
||||||
|
return c.Param
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ColumnInfo) TitleArrow() string {
|
||||||
|
if c.Sorted == "asc" {
|
||||||
|
return "↑"
|
||||||
|
} else if c.Sorted == "desc" {
|
||||||
|
return "↓"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Create creates a new web server instance and sets up routing.
|
// Create creates a new web server instance and sets up routing.
|
||||||
func Create(bmm *db.BookmarkManager, cmm *db.ConfigManager) *Server {
|
func Create(bmm *db.BookmarkManager, cmm *db.ConfigManager) *Server {
|
||||||
|
|
||||||
@@ -92,13 +115,42 @@ func Create(bmm *db.BookmarkManager, cmm *db.ConfigManager) *Server {
|
|||||||
r.POST("/manage/results", func(c *gin.Context) {
|
r.POST("/manage/results", func(c *gin.Context) {
|
||||||
query := c.PostForm("query")
|
query := c.PostForm("query")
|
||||||
tags := []string{}
|
tags := []string{}
|
||||||
|
sort := c.Query("sort")
|
||||||
|
|
||||||
if c.PostForm("tags_hidden") != "" {
|
if c.PostForm("tags_hidden") != "" {
|
||||||
tags = strings.Split(c.PostForm("tags_hidden"), "|")
|
tags = strings.Split(c.PostForm("tags_hidden"), "|")
|
||||||
}
|
}
|
||||||
allBookmarks, _ := bmm.Search(db.SearchOptions{Query: query, Tags: tags})
|
allBookmarks, _ := bmm.Search(db.SearchOptions{Query: query, Tags: tags, Sort: sort})
|
||||||
meta := gin.H{"config": config, "bookmarks": allBookmarks}
|
meta := gin.H{"config": config, "bookmarks": allBookmarks}
|
||||||
|
|
||||||
log.Printf("query is %s, tags %v", query, tags)
|
colTitle := &ColumnInfo{Name: "Title/URL", Param: "title"}
|
||||||
|
colCreated := &ColumnInfo{Name: "Created", Param: "created", Class: "show-for-large"}
|
||||||
|
colScraped := &ColumnInfo{Name: "Scraped", Param: "scraped", Class: "show-for-large"}
|
||||||
|
if sort == "title" {
|
||||||
|
colTitle.Sorted = "asc"
|
||||||
|
}
|
||||||
|
if sort == "-title" {
|
||||||
|
colTitle.Sorted = "desc"
|
||||||
|
}
|
||||||
|
if sort == "scraped" {
|
||||||
|
colScraped.Sorted = "asc"
|
||||||
|
}
|
||||||
|
if sort == "-scraped" {
|
||||||
|
colScraped.Sorted = "desc"
|
||||||
|
}
|
||||||
|
if sort == "created" {
|
||||||
|
colCreated.Sorted = "asc"
|
||||||
|
}
|
||||||
|
if sort == "-created" {
|
||||||
|
colCreated.Sorted = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
|
cols := gin.H{
|
||||||
|
"title": colTitle,
|
||||||
|
"created": colCreated,
|
||||||
|
"scraped": colScraped,
|
||||||
|
}
|
||||||
|
meta["column"] = cols
|
||||||
|
|
||||||
c.HTML(http.StatusOK,
|
c.HTML(http.StatusOK,
|
||||||
"manage_results.html", meta,
|
"manage_results.html", meta,
|
||||||
@@ -350,7 +402,10 @@ func cleanupTags(tags []string) []string {
|
|||||||
keys := make(map[string]struct{})
|
keys := make(map[string]struct{})
|
||||||
for _, k := range tags {
|
for _, k := range tags {
|
||||||
if k != "" && k != "|" {
|
if k != "" && k != "|" {
|
||||||
keys[strings.ToLower(k)] = struct{}{}
|
for _, subKey := range strings.Split(k, ",") {
|
||||||
|
subKey := strings.Trim(subKey, " ")
|
||||||
|
keys[strings.ToLower(subKey)] = struct{}{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out := []string{}
|
out := []string{}
|
||||||
@@ -374,6 +429,7 @@ func niceTime(t time.Time) timeVariations {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ago := durafmt.Parse(time.Since(t)).LimitFirstN(1).Format(units)
|
ago := durafmt.Parse(time.Since(t)).LimitFirstN(1).Format(units)
|
||||||
|
ago = strings.ReplaceAll(ago, " ", "")
|
||||||
|
|
||||||
return timeVariations{HumanDuration: ago}
|
return timeVariations{HumanDuration: ago}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user