mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
feat(releases): show indexer name instead of identifier (#1706)
* feat(releases): show indexer name instead of identifier * feat(releases): remove log in Cell * feat(releases): update Dashboard recent releases * fix(releases): db tests * fix(releases): remove unused code * fix(releases): remove more unused code * fix(releases): remove even more unused code --------- Co-authored-by: martylukyy <35452459+martylukyy@users.noreply.github.com>
This commit is contained in:
parent
54eab05f1f
commit
fd90020400
7 changed files with 76 additions and 200 deletions
|
@ -97,19 +97,19 @@ func (repo *ReleaseRepo) StoreReleaseActionStatus(ctx context.Context, status *d
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryParams) ([]*domain.Release, int64, int64, error) {
|
func (repo *ReleaseRepo) Find(ctx context.Context, params domain.ReleaseQueryParams) (*domain.FindReleasesResponse, error) {
|
||||||
tx, err := repo.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
|
tx, err := repo.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, errors.Wrap(err, "error begin transaction")
|
return nil, errors.Wrap(err, "error begin transaction")
|
||||||
}
|
}
|
||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
releases, nextCursor, total, err := repo.findReleases(ctx, tx, params)
|
resp, err := repo.findReleases(ctx, tx, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nextCursor, total, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return releases, nextCursor, total, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var reservedSearch = map[string]*regexp.Regexp{
|
var reservedSearch = map[string]*regexp.Regexp{
|
||||||
|
@ -126,7 +126,7 @@ var reservedSearch = map[string]*regexp.Regexp{
|
||||||
"r.filter": regexp.MustCompile(`(?i)(?:` + `filter` + `:)(?P<value>'.*?'|".*?"|\S+)`),
|
"r.filter": regexp.MustCompile(`(?i)(?:` + `filter` + `:)(?P<value>'.*?'|".*?"|\S+)`),
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain.ReleaseQueryParams) ([]*domain.Release, int64, int64, error) {
|
func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain.ReleaseQueryParams) (*domain.FindReleasesResponse, error) {
|
||||||
whereQueryBuilder := sq.And{}
|
whereQueryBuilder := sq.And{}
|
||||||
if params.Cursor > 0 {
|
if params.Cursor > 0 {
|
||||||
whereQueryBuilder = append(whereQueryBuilder, sq.Lt{"r.id": params.Cursor})
|
whereQueryBuilder = append(whereQueryBuilder, sq.Lt{"r.id": params.Cursor})
|
||||||
|
@ -172,7 +172,7 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
|
||||||
|
|
||||||
whereQuery, _, err := whereQueryBuilder.ToSql()
|
whereQuery, _, err := whereQueryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, errors.Wrap(err, "error building wherequery")
|
return nil, errors.Wrap(err, "error building wherequery")
|
||||||
}
|
}
|
||||||
|
|
||||||
subQueryBuilder := repo.db.squirrel.
|
subQueryBuilder := repo.db.squirrel.
|
||||||
|
@ -206,53 +206,57 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
|
||||||
|
|
||||||
subQuery, subArgs, err := subQueryBuilder.ToSql()
|
subQuery, subArgs, err := subQueryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, errors.Wrap(err, "error building subquery")
|
return nil, errors.Wrap(err, "error building subquery")
|
||||||
}
|
}
|
||||||
|
|
||||||
queryBuilder := repo.db.squirrel.
|
queryBuilder := repo.db.squirrel.
|
||||||
Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "r.filter", "r.protocol", "r.info_url", "r.download_url", "r.title", "r.torrent_name", "r.size", "r.category", "r.season", "r.episode", "r.year", "r.resolution", "r.source", "r.codec", "r.container", "r.release_group", "r.timestamp",
|
Select("r.id", "r.filter_status", "r.rejections", "r.indexer", "i.id", "i.name", "i.identifier_external", "r.filter", "r.protocol", "r.info_url", "r.download_url", "r.title", "r.torrent_name", "r.size", "r.category", "r.season", "r.episode", "r.year", "r.resolution", "r.source", "r.codec", "r.container", "r.release_group", "r.timestamp",
|
||||||
"ras.id", "ras.status", "ras.action", "ras.action_id", "ras.type", "ras.client", "ras.filter", "ras.filter_id", "ras.release_id", "ras.rejections", "ras.timestamp").
|
"ras.id", "ras.status", "ras.action", "ras.action_id", "ras.type", "ras.client", "ras.filter", "ras.filter_id", "ras.release_id", "ras.rejections", "ras.timestamp").
|
||||||
Column(sq.Alias(countQuery, "page_total")).
|
Column(sq.Alias(countQuery, "page_total")).
|
||||||
From("release r").
|
From("release r").
|
||||||
OrderBy("r.id DESC").
|
OrderBy("r.id DESC").
|
||||||
Where("r.id IN ("+subQuery+")", subArgs...).
|
Where("r.id IN ("+subQuery+")", subArgs...).
|
||||||
LeftJoin("release_action_status ras ON r.id = ras.release_id")
|
LeftJoin("release_action_status ras ON r.id = ras.release_id").
|
||||||
|
LeftJoin("indexer i ON r.indexer = i.identifier")
|
||||||
|
|
||||||
query, args, err := queryBuilder.ToSql()
|
query, args, err := queryBuilder.ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, errors.Wrap(err, "error building query")
|
return nil, errors.Wrap(err, "error building query")
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.log.Trace().Str("database", "release.find").Msgf("query: '%v', args: '%v'", query, args)
|
repo.log.Trace().Str("database", "release.find").Msgf("query: '%v', args: '%v'", query, args)
|
||||||
|
|
||||||
res := make([]*domain.Release, 0)
|
resp := &domain.FindReleasesResponse{
|
||||||
|
Data: make([]*domain.Release, 0),
|
||||||
|
TotalCount: 0,
|
||||||
|
NextCursor: 0,
|
||||||
|
}
|
||||||
|
|
||||||
rows, err := tx.QueryContext(ctx, query, args...)
|
rows, err := tx.QueryContext(ctx, query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, errors.Wrap(err, "error executing query")
|
return resp, errors.Wrap(err, "error executing query")
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
return res, 0, 0, errors.Wrap(err, "error rows findreleases")
|
return resp, errors.Wrap(err, "error rows findreleases")
|
||||||
}
|
}
|
||||||
|
|
||||||
var countItems int64 = 0
|
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var rls domain.Release
|
var rls domain.Release
|
||||||
var ras domain.ReleaseActionStatus
|
var ras domain.ReleaseActionStatus
|
||||||
|
|
||||||
var rlsindexer, rlsfilter, infoUrl, downloadUrl, codec sql.NullString
|
var rlsIndexer, rlsIndexerName, rlsIndexerExternalName, rlsFilter, infoUrl, downloadUrl, codec sql.NullString
|
||||||
|
|
||||||
|
var rlsIndexerID sql.NullInt64
|
||||||
var rasId, rasFilterId, rasReleaseId, rasActionId sql.NullInt64
|
var rasId, rasFilterId, rasReleaseId, rasActionId sql.NullInt64
|
||||||
var rasStatus, rasAction, rasType, rasClient, rasFilter sql.NullString
|
var rasStatus, rasAction, rasType, rasClient, rasFilter sql.NullString
|
||||||
var rasRejections []sql.NullString
|
var rasRejections []sql.NullString
|
||||||
var rasTimestamp sql.NullTime
|
var rasTimestamp sql.NullTime
|
||||||
|
|
||||||
if err := rows.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &rlsindexer, &rlsfilter, &rls.Protocol, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &rls.Size, &rls.Category, &rls.Season, &rls.Episode, &rls.Year, &rls.Resolution, &rls.Source, &codec, &rls.Container, &rls.Group, &rls.Timestamp, &rasId, &rasStatus, &rasAction, &rasActionId, &rasType, &rasClient, &rasFilter, &rasFilterId, &rasReleaseId, pq.Array(&rasRejections), &rasTimestamp, &countItems); err != nil {
|
if err := rows.Scan(&rls.ID, &rls.FilterStatus, pq.Array(&rls.Rejections), &rlsIndexer, &rlsIndexerID, &rlsIndexerName, &rlsIndexerExternalName, &rlsFilter, &rls.Protocol, &infoUrl, &downloadUrl, &rls.Title, &rls.TorrentName, &rls.Size, &rls.Category, &rls.Season, &rls.Episode, &rls.Year, &rls.Resolution, &rls.Source, &codec, &rls.Container, &rls.Group, &rls.Timestamp, &rasId, &rasStatus, &rasAction, &rasActionId, &rasType, &rasClient, &rasFilter, &rasFilterId, &rasReleaseId, pq.Array(&rasRejections), &rasTimestamp, &resp.TotalCount); err != nil {
|
||||||
return res, 0, 0, errors.Wrap(err, "error scanning row")
|
return resp, errors.Wrap(err, "error scanning row")
|
||||||
}
|
}
|
||||||
|
|
||||||
//for _, codec := range codecs {
|
//for _, codec := range codecs {
|
||||||
|
@ -277,21 +281,25 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
|
||||||
}
|
}
|
||||||
|
|
||||||
idx := 0
|
idx := 0
|
||||||
for ; idx < len(res); idx++ {
|
for ; idx < len(resp.Data); idx++ {
|
||||||
if res[idx].ID != rls.ID {
|
if resp.Data[idx].ID != rls.ID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
res[idx].ActionStatus = append(res[idx].ActionStatus, ras)
|
resp.Data[idx].ActionStatus = append(resp.Data[idx].ActionStatus, ras)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if idx != len(res) {
|
if idx != len(resp.Data) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rls.Indexer.Identifier = rlsindexer.String
|
rls.Indexer.Identifier = rlsIndexer.String
|
||||||
rls.FilterName = rlsfilter.String
|
rls.Indexer.ID = int(rlsIndexerID.Int64)
|
||||||
|
rls.Indexer.Name = rlsIndexerName.String
|
||||||
|
rls.Indexer.IdentifierExternal = rlsIndexerExternalName.String
|
||||||
|
|
||||||
|
rls.FilterName = rlsFilter.String
|
||||||
rls.ActionStatus = make([]domain.ReleaseActionStatus, 0)
|
rls.ActionStatus = make([]domain.ReleaseActionStatus, 0)
|
||||||
rls.InfoURL = infoUrl.String
|
rls.InfoURL = infoUrl.String
|
||||||
rls.DownloadURL = downloadUrl.String
|
rls.DownloadURL = downloadUrl.String
|
||||||
|
@ -302,31 +310,15 @@ func (repo *ReleaseRepo) findReleases(ctx context.Context, tx *Tx, params domain
|
||||||
rls.ActionStatus = append(rls.ActionStatus, ras)
|
rls.ActionStatus = append(rls.ActionStatus, ras)
|
||||||
}
|
}
|
||||||
|
|
||||||
res = append(res, &rls)
|
resp.Data = append(resp.Data, &rls)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextCursor := int64(0)
|
if len(resp.Data) > 0 {
|
||||||
if len(res) > 0 {
|
lastID := resp.Data[len(resp.Data)-1].ID
|
||||||
lastID := res[len(res)-1].ID
|
resp.NextCursor = lastID
|
||||||
nextCursor = lastID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nextCursor, countItems, nil
|
return resp, nil
|
||||||
}
|
|
||||||
|
|
||||||
func (repo *ReleaseRepo) FindRecent(ctx context.Context) ([]*domain.Release, error) {
|
|
||||||
tx, err := repo.db.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "error begin transaction")
|
|
||||||
}
|
|
||||||
defer tx.Rollback()
|
|
||||||
|
|
||||||
releases, _, _, err := repo.findReleases(ctx, tx, domain.ReleaseQueryParams{Limit: 10})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return releases, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ReleaseRepo) GetIndexerOptions(ctx context.Context) ([]string, error) {
|
func (repo *ReleaseRepo) GetIndexerOptions(ctx context.Context) ([]string, error) {
|
||||||
|
|
|
@ -231,12 +231,12 @@ func TestReleaseRepo_Find(t *testing.T) {
|
||||||
Search: "",
|
Search: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, nextCursor, total, err := repo.Find(context.Background(), queryParams)
|
resp, err := repo.Find(context.Background(), queryParams)
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
assert.NotNil(t, releases)
|
assert.NotNil(t, resp)
|
||||||
assert.NotEqual(t, int64(0), total)
|
assert.NotEqual(t, int64(0), resp.TotalCount)
|
||||||
assert.True(t, nextCursor >= 0)
|
assert.True(t, resp.NextCursor >= 0)
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
_ = repo.Delete(context.Background(), &domain.DeleteReleaseRequest{OlderThan: 0})
|
_ = repo.Delete(context.Background(), &domain.DeleteReleaseRequest{OlderThan: 0})
|
||||||
|
@ -281,11 +281,11 @@ func TestReleaseRepo_FindRecent(t *testing.T) {
|
||||||
err = repo.Store(context.Background(), mockData)
|
err = repo.Store(context.Background(), mockData)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
releases, err := repo.FindRecent(context.Background())
|
resp, err := repo.Find(context.Background(), domain.ReleaseQueryParams{Limit: 10})
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
assert.NotNil(t, releases)
|
assert.NotNil(t, resp.Data)
|
||||||
assert.Lenf(t, releases, 1, "Expected 1 release, got %d", len(releases))
|
assert.Lenf(t, resp.Data, 1, "Expected 1 release, got %d", len(resp.Data))
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
_ = repo.Delete(context.Background(), &domain.DeleteReleaseRequest{OlderThan: 0})
|
_ = repo.Delete(context.Background(), &domain.DeleteReleaseRequest{OlderThan: 0})
|
||||||
|
|
|
@ -31,8 +31,7 @@ import (
|
||||||
|
|
||||||
type ReleaseRepo interface {
|
type ReleaseRepo interface {
|
||||||
Store(ctx context.Context, release *Release) error
|
Store(ctx context.Context, release *Release) error
|
||||||
Find(ctx context.Context, params ReleaseQueryParams) (res []*Release, nextCursor int64, count int64, err error)
|
Find(ctx context.Context, params ReleaseQueryParams) (*FindReleasesResponse, error)
|
||||||
FindRecent(ctx context.Context) ([]*Release, error)
|
|
||||||
Get(ctx context.Context, req *GetReleaseRequest) (*Release, error)
|
Get(ctx context.Context, req *GetReleaseRequest) (*Release, error)
|
||||||
GetIndexerOptions(ctx context.Context) ([]string, error)
|
GetIndexerOptions(ctx context.Context) ([]string, error)
|
||||||
Stats(ctx context.Context) (*ReleaseStats, error)
|
Stats(ctx context.Context) (*ReleaseStats, error)
|
||||||
|
@ -271,6 +270,12 @@ type ReleaseQueryParams struct {
|
||||||
Search string
|
Search string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FindReleasesResponse struct {
|
||||||
|
Data []*Release `json:"data"`
|
||||||
|
TotalCount uint64 `json:"count"`
|
||||||
|
NextCursor int64 `json:"next_cursor"`
|
||||||
|
}
|
||||||
|
|
||||||
type ReleaseActionRetryReq struct {
|
type ReleaseActionRetryReq struct {
|
||||||
ReleaseId int
|
ReleaseId int
|
||||||
ActionStatusId int
|
ActionStatusId int
|
||||||
|
|
|
@ -18,8 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type releaseService interface {
|
type releaseService interface {
|
||||||
Find(ctx context.Context, query domain.ReleaseQueryParams) (res []*domain.Release, nextCursor int64, count int64, err error)
|
Find(ctx context.Context, query domain.ReleaseQueryParams) (*domain.FindReleasesResponse, error)
|
||||||
FindRecent(ctx context.Context) (res []*domain.Release, err error)
|
|
||||||
Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error)
|
Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error)
|
||||||
GetIndexerOptions(ctx context.Context) ([]string, error)
|
GetIndexerOptions(ctx context.Context) ([]string, error)
|
||||||
Stats(ctx context.Context) (*domain.ReleaseStats, error)
|
Stats(ctx context.Context) (*domain.ReleaseStats, error)
|
||||||
|
@ -128,7 +127,7 @@ func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
|
||||||
Search: search,
|
Search: search,
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, nextCursor, count, err := h.service.Find(r.Context(), query)
|
resp, err := h.service.Find(r.Context(), query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.encoder.StatusResponse(w, http.StatusInternalServerError, map[string]any{
|
h.encoder.StatusResponse(w, http.StatusInternalServerError, map[string]any{
|
||||||
"code": "INTERNAL_SERVER_ERROR",
|
"code": "INTERNAL_SERVER_ERROR",
|
||||||
|
@ -137,21 +136,11 @@ func (h releaseHandler) findReleases(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := struct {
|
h.encoder.StatusResponse(w, http.StatusOK, resp)
|
||||||
Data []*domain.Release `json:"data"`
|
|
||||||
NextCursor int64 `json:"next_cursor"`
|
|
||||||
Count int64 `json:"count"`
|
|
||||||
}{
|
|
||||||
Data: releases,
|
|
||||||
NextCursor: nextCursor,
|
|
||||||
Count: count,
|
|
||||||
}
|
|
||||||
|
|
||||||
h.encoder.StatusResponse(w, http.StatusOK, ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h releaseHandler) findRecentReleases(w http.ResponseWriter, r *http.Request) {
|
func (h releaseHandler) findRecentReleases(w http.ResponseWriter, r *http.Request) {
|
||||||
releases, err := h.service.FindRecent(r.Context())
|
resp, err := h.service.Find(r.Context(), domain.ReleaseQueryParams{Limit: 10})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.encoder.StatusResponse(w, http.StatusInternalServerError, map[string]any{
|
h.encoder.StatusResponse(w, http.StatusInternalServerError, map[string]any{
|
||||||
"code": "INTERNAL_SERVER_ERROR",
|
"code": "INTERNAL_SERVER_ERROR",
|
||||||
|
@ -160,13 +149,7 @@ func (h releaseHandler) findRecentReleases(w http.ResponseWriter, r *http.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ret := struct {
|
h.encoder.StatusResponse(w, http.StatusOK, resp)
|
||||||
Data []*domain.Release `json:"data"`
|
|
||||||
}{
|
|
||||||
Data: releases,
|
|
||||||
}
|
|
||||||
|
|
||||||
h.encoder.StatusResponse(w, http.StatusOK, ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h releaseHandler) getReleaseByID(w http.ResponseWriter, r *http.Request) {
|
func (h releaseHandler) getReleaseByID(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -19,8 +19,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
Find(ctx context.Context, query domain.ReleaseQueryParams) (res []*domain.Release, nextCursor int64, count int64, err error)
|
Find(ctx context.Context, query domain.ReleaseQueryParams) (*domain.FindReleasesResponse, error)
|
||||||
FindRecent(ctx context.Context) ([]*domain.Release, error)
|
|
||||||
Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error)
|
Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error)
|
||||||
GetActionStatus(ctx context.Context, req *domain.GetReleaseActionStatusRequest) (*domain.ReleaseActionStatus, error)
|
GetActionStatus(ctx context.Context, req *domain.GetReleaseActionStatusRequest) (*domain.ReleaseActionStatus, error)
|
||||||
GetIndexerOptions(ctx context.Context) ([]string, error)
|
GetIndexerOptions(ctx context.Context) ([]string, error)
|
||||||
|
@ -58,14 +57,10 @@ func NewService(log logger.Logger, repo domain.ReleaseRepo, actionSvc action.Ser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) Find(ctx context.Context, query domain.ReleaseQueryParams) (res []*domain.Release, nextCursor int64, count int64, err error) {
|
func (s *service) Find(ctx context.Context, query domain.ReleaseQueryParams) (*domain.FindReleasesResponse, error) {
|
||||||
return s.repo.Find(ctx, query)
|
return s.repo.Find(ctx, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) FindRecent(ctx context.Context) (res []*domain.Release, err error) {
|
|
||||||
return s.repo.FindRecent(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error) {
|
func (s *service) Get(ctx context.Context, req *domain.GetReleaseRequest) (*domain.Release, error) {
|
||||||
return s.repo.Get(ctx, req)
|
return s.repo.Get(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,23 +110,23 @@ export const AgeCell = ({value}: CellProps<Release>) => (
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const IndexerCell = ({value}: CellProps<Release>) => (
|
export const IndexerCell = (props: CellProps<Release>) => (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"py-3 text-sm font-medium box-content text-gray-900 dark:text-gray-300",
|
"py-3 text-sm font-medium box-content text-gray-900 dark:text-gray-300",
|
||||||
"max-w-[96px] sm:max-w-[216px] md:max-w-[360px] lg:max-w-[640px] xl:max-w-[840px]"
|
"max-w-[96px] sm:max-w-[216px] md:max-w-[360px] lg:max-w-[640px] xl:max-w-[840px]"
|
||||||
)}
|
)}
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
requiresClick
|
|
||||||
label={value}
|
|
||||||
maxWidth="max-w-[90vw]"
|
|
||||||
>
|
>
|
||||||
|
<Tooltip
|
||||||
|
requiresClick
|
||||||
|
label={props.row.original.indexer.name ? props.row.original.indexer.name : props.row.original.indexer.identifier}
|
||||||
|
maxWidth="max-w-[90vw]"
|
||||||
|
>
|
||||||
<span className="whitespace-pre-wrap break-words">
|
<span className="whitespace-pre-wrap break-words">
|
||||||
{value}
|
{props.row.original.indexer.name ? props.row.original.indexer.name : props.row.original.indexer.identifier}
|
||||||
</span>
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const TitleCell = ({value}: CellProps<Release>) => (
|
export const TitleCell = ({value}: CellProps<Release>) => (
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { Suspense, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
useTable,
|
useTable,
|
||||||
|
@ -18,8 +18,8 @@ import { EmptyListState } from "@components/emptystates";
|
||||||
import * as Icons from "@components/Icons";
|
import * as Icons from "@components/Icons";
|
||||||
import * as DataTable from "@components/data-table";
|
import * as DataTable from "@components/data-table";
|
||||||
import { RandomLinuxIsos } from "@utils";
|
import { RandomLinuxIsos } from "@utils";
|
||||||
import { RingResizeSpinner } from "@components/Icons";
|
|
||||||
import { ReleasesLatestQueryOptions } from "@api/queries";
|
import { ReleasesLatestQueryOptions } from "@api/queries";
|
||||||
|
import { IndexerCell } from "@components/data-table";
|
||||||
|
|
||||||
// This is a custom filter UI for selecting
|
// This is a custom filter UI for selecting
|
||||||
// a unique option from a list
|
// a unique option from a list
|
||||||
|
@ -166,28 +166,6 @@ function Table({ columns, data }: TableProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RecentActivityTable = () => {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col mt-12">
|
|
||||||
<h3 className="text-2xl font-medium leading-6 text-gray-900 dark:text-gray-200">
|
|
||||||
Recent activity
|
|
||||||
</h3>
|
|
||||||
<div className="animate-pulse text-black dark:text-white">
|
|
||||||
<Suspense
|
|
||||||
fallback={
|
|
||||||
<div className="flex items-center justify-center lg:col-span-9">
|
|
||||||
<RingResizeSpinner className="text-blue-500 size-12" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{/*<EmptyListState text="Loading..."/>*/}
|
|
||||||
<ActivityTableContent />
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ActivityTable = () => {
|
export const ActivityTable = () => {
|
||||||
const columns = React.useMemo(() => [
|
const columns = React.useMemo(() => [
|
||||||
{
|
{
|
||||||
|
@ -208,7 +186,7 @@ export const ActivityTable = () => {
|
||||||
{
|
{
|
||||||
Header: "Indexer",
|
Header: "Indexer",
|
||||||
accessor: "indexer.identifier",
|
accessor: "indexer.identifier",
|
||||||
Cell: DataTable.TitleCell,
|
Cell: IndexerCell,
|
||||||
Filter: SelectColumnFilter,
|
Filter: SelectColumnFilter,
|
||||||
filter: "includes"
|
filter: "includes"
|
||||||
}
|
}
|
||||||
|
@ -275,80 +253,3 @@ export const ActivityTable = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActivityTableContent = () => {
|
|
||||||
const columns = React.useMemo(() => [
|
|
||||||
{
|
|
||||||
Header: "Age",
|
|
||||||
accessor: "timestamp",
|
|
||||||
Cell: DataTable.AgeCell
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: "Release",
|
|
||||||
accessor: "name",
|
|
||||||
Cell: DataTable.TitleCell
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: "Actions",
|
|
||||||
accessor: "action_status",
|
|
||||||
Cell: DataTable.ReleaseStatusCell
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: "Indexer",
|
|
||||||
accessor: "indexer.identifier",
|
|
||||||
Cell: DataTable.TitleCell,
|
|
||||||
Filter: SelectColumnFilter,
|
|
||||||
filter: "includes"
|
|
||||||
}
|
|
||||||
] as Column[], []);
|
|
||||||
|
|
||||||
const { isLoading, data } = useSuspenseQuery(ReleasesLatestQueryOptions());
|
|
||||||
|
|
||||||
const [modifiedData, setModifiedData] = useState<Release[]>([]);
|
|
||||||
const [showLinuxIsos, setShowLinuxIsos] = useState(false);
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<EmptyListState text="Loading..."/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleReleaseNames = () => {
|
|
||||||
setShowLinuxIsos(!showLinuxIsos);
|
|
||||||
if (!showLinuxIsos && data && data.data) {
|
|
||||||
const randomNames = RandomLinuxIsos(data.data.length);
|
|
||||||
const newData: Release[] = data.data.map((item, index) => ({
|
|
||||||
...item,
|
|
||||||
name: `${randomNames[index]}.iso`,
|
|
||||||
indexer: {
|
|
||||||
id: 0,
|
|
||||||
name: index % 2 === 0 ? "distrowatch" : "linuxtracker",
|
|
||||||
identifier: index % 2 === 0 ? "distrowatch" : "linuxtracker",
|
|
||||||
identifier_external: index % 2 === 0 ? "distrowatch" : "linuxtracker",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
setModifiedData(newData);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const displayData = showLinuxIsos ? modifiedData : (data?.data ?? []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Table columns={columns} data={displayData} />
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={toggleReleaseNames}
|
|
||||||
className="p-2 absolute -bottom-8 right-0 bg-gray-750 text-white rounded-full opacity-10 hover:opacity-100 transition-opacity duration-300"
|
|
||||||
aria-label="Toggle view"
|
|
||||||
title="Go incognito"
|
|
||||||
>
|
|
||||||
{showLinuxIsos ? (
|
|
||||||
<EyeIcon className="h-4 w-4" />
|
|
||||||
) : (
|
|
||||||
<EyeSlashIcon className="h-4 w-4" />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue