added Edit Group button to mock sync group accordion
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
|
|
||||||
"ruben/inventory2/consts"
|
"ruben/inventory2/consts"
|
||||||
@@ -500,6 +501,97 @@ func (db *Store) DeleteMockSyncGroup(ctx context.Context, acctID, syncGroupID in
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *Store) StartEditingMockSyncGroup(ctx context.Context, acctID, syncGroupID int64) (int64, bool, error) {
|
||||||
|
rows, err := db.db.Query(
|
||||||
|
ctx,
|
||||||
|
`
|
||||||
|
WITH deleted_row AS (
|
||||||
|
DELETE FROM
|
||||||
|
mock.sync_group_editing
|
||||||
|
WHERE
|
||||||
|
account_id = @account_id
|
||||||
|
AND sync_group_id <> @sync_group_id
|
||||||
|
RETURNING
|
||||||
|
account_id,
|
||||||
|
sync_group_id
|
||||||
|
), new_row AS (
|
||||||
|
INSERT INTO
|
||||||
|
mock.sync_group_editing (
|
||||||
|
account_id,
|
||||||
|
sync_group_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
x.account_id,
|
||||||
|
x.sync_group_id
|
||||||
|
FROM (
|
||||||
|
VALUES (
|
||||||
|
@account_id,
|
||||||
|
@sync_group_id
|
||||||
|
)
|
||||||
|
) AS x(account_id, sync_group_id)
|
||||||
|
LEFT JOIN
|
||||||
|
deleted_row
|
||||||
|
ON
|
||||||
|
TRUE
|
||||||
|
ON CONFLICT
|
||||||
|
DO NOTHING
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
sync_group_id
|
||||||
|
FROM
|
||||||
|
deleted_row
|
||||||
|
`,
|
||||||
|
pgx.NamedArgs{
|
||||||
|
"account_id": acctID,
|
||||||
|
"sync_group_id": syncGroupID,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return 0, false, fmt.Errorf("failed to perform query: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := pgx.CollectExactlyOneRow(rows, pgx.RowTo[pgtype.Int8])
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return 0, false, nil
|
||||||
|
}
|
||||||
|
return 0, false, fmt.Errorf("failed to scan rows: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.Int64, v.Valid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Store) MockSyncGroupIsBeingEdited(ctx context.Context, acctID, syncGroupID int64) (bool, error) {
|
||||||
|
rows, err := db.db.Query(
|
||||||
|
ctx,
|
||||||
|
`
|
||||||
|
SELECT
|
||||||
|
true
|
||||||
|
FROM
|
||||||
|
mock.sync_group_editing
|
||||||
|
WHERE
|
||||||
|
account_id = @account_id
|
||||||
|
AND sync_group_id = @sync_group_id
|
||||||
|
`,
|
||||||
|
pgx.NamedArgs{
|
||||||
|
"account_id": acctID,
|
||||||
|
"sync_group_id": syncGroupID,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to perform query: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = pgx.CollectExactlyOneRow(rows, pgx.RowTo[pgtype.Bool]); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("failed to scan rows: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// additional context
|
// additional context
|
||||||
|
|
||||||
func (db *Store) GetAccountPointerByUserID(ctx context.Context, userID string) (*Account, error) {
|
func (db *Store) GetAccountPointerByUserID(ctx context.Context, userID string) (*Account, error) {
|
||||||
|
|||||||
@@ -65,6 +65,14 @@ func (v_ctx *StoreWithContext) DeleteMockSyncGroup(acctID int64, syncGroupID int
|
|||||||
return v_ctx.Store.DeleteMockSyncGroup(v_ctx.ctx, acctID, syncGroupID)
|
return v_ctx.Store.DeleteMockSyncGroup(v_ctx.ctx, acctID, syncGroupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v_ctx *StoreWithContext) StartEditingMockSyncGroup(acctID int64, syncGroupID int64) (int64, bool, error) {
|
||||||
|
return v_ctx.Store.StartEditingMockSyncGroup(v_ctx.ctx, acctID, syncGroupID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v_ctx *StoreWithContext) MockSyncGroupIsBeingEdited(acctID int64, syncGroupID int64) (bool, error) {
|
||||||
|
return v_ctx.Store.MockSyncGroupIsBeingEdited(v_ctx.ctx, acctID, syncGroupID)
|
||||||
|
}
|
||||||
|
|
||||||
func (v_ctx *StoreWithContext) GetAccountPointerByUserID(userID string) (*Account, error) {
|
func (v_ctx *StoreWithContext) GetAccountPointerByUserID(userID string) (*Account, error) {
|
||||||
return v_ctx.Store.GetAccountPointerByUserID(v_ctx.ctx, userID)
|
return v_ctx.Store.GetAccountPointerByUserID(v_ctx.ctx, userID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ func Routes(
|
|||||||
mockSyncGroups := syncGroups.Group("/mock")
|
mockSyncGroups := syncGroups.Group("/mock")
|
||||||
mockSyncGroups.POST("", pub.Publish("/:acctID/inventory/sync-groups/mock"), response.Handler(as.saveNewMockSyncGroup))
|
mockSyncGroups.POST("", pub.Publish("/:acctID/inventory/sync-groups/mock"), response.Handler(as.saveNewMockSyncGroup))
|
||||||
mockSyncGroups.DELETE("/:syncGroupID", pub.Publish("/:acctID/inventory/sync-groups/mock"), response.Handler(as.deleteMockSyncGroup))
|
mockSyncGroups.DELETE("/:syncGroupID", pub.Publish("/:acctID/inventory/sync-groups/mock"), response.Handler(as.deleteMockSyncGroup))
|
||||||
|
mockSyncGroups.PUT("/editing", pub.Publish("/:acctID/inventory/sync-groups/mock/editing"), response.Handler(as.selectMockSyncGroupForEditing))
|
||||||
|
|
||||||
mockDraftListings := mockSyncGroups.Group("/draft/listings", pub.Publish("/:acctID/inventory/sync-groups/mock/draft/listings"))
|
mockDraftListings := mockSyncGroups.Group("/draft/listings", pub.Publish("/:acctID/inventory/sync-groups/mock/draft/listings"))
|
||||||
mockDraftListings.POST("", response.Handler(as.createMockSyncGroupListingDraft))
|
mockDraftListings.POST("", response.Handler(as.createMockSyncGroupListingDraft))
|
||||||
@@ -534,6 +535,41 @@ func (s *accountSubrouter) deleteMockSyncGroup(c *gin.Context) (response.Respons
|
|||||||
return response.StatusCreated(), nil
|
return response.StatusCreated(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PUT /:acctID/inventory/sync-groups/mock/editing
|
||||||
|
func (s *accountSubrouter) selectMockSyncGroupForEditing(c *gin.Context) (response.Response, error) {
|
||||||
|
r := c.Request
|
||||||
|
ctx := r.Context()
|
||||||
|
acctID := auth.GetIdentity(ctx).Account.AccountID
|
||||||
|
|
||||||
|
var (
|
||||||
|
syncGroupID int64
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := param.Form("syncGroupID", param.Int64(&syncGroupID)).
|
||||||
|
Unmarshal(c); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prevSyncGroupID, ok, err := s.accts.StartEditingMockSyncGroup(ctx, acctID, syncGroupID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, response.Errorf("failed to save new mock sync group: %w", response.ErrorFromConstant(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// emit events indicating sync groups being edited and no longer being edited
|
||||||
|
|
||||||
|
evts := make([]string, 1, 2)
|
||||||
|
evts[0] = fmt.Sprintf("accounts_%d_inventory_sync-groups_mock_%d", acctID, syncGroupID)
|
||||||
|
if ok {
|
||||||
|
evts = append(evts, fmt.Sprintf("accounts_%d_inventory_sync-groups_mock_%d", acctID, prevSyncGroupID))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.pub.Push(c, acctID, evts...); err != nil {
|
||||||
|
s.log.Errorf("failed to publish mock sync group editing events: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.StatusOK(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func lowerSnakeCase(s accounts.Platform) string {
|
func lowerSnakeCase(s accounts.Platform) string {
|
||||||
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
|
return strings.ToLower(strings.Join(strings.Split(string(s), " "), "_"))
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-11
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
{{- $syncGroupID := .PathParams.syncGroupID }}
|
{{- $syncGroupID := .PathParams.syncGroupID }}
|
||||||
{{- $acctID := .PathParams.acctID }}
|
{{- $acctID := .PathParams.acctID }}
|
||||||
|
{{- $open := false }}
|
||||||
|
{{- if .Request }}
|
||||||
|
{{- $open = eq (.Request.URL.Query.Get "open") "true" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{- $grp := .SyncGroup }}
|
{{- $grp := .SyncGroup }}
|
||||||
{{- if not $grp }}
|
{{- if not $grp }}
|
||||||
@@ -9,11 +13,15 @@
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
|
||||||
|
{{- $id := (printf "sync-group-%d" $syncGroupID) }}
|
||||||
<li
|
<li
|
||||||
id="sync-group-{{$grp.SyncGroupID}}"
|
id="{{$id}}"
|
||||||
class="
|
class="mx-[1em]"
|
||||||
mx-[1em]
|
hx-get="{{ printf "/ui/accounts/%d/inventory/sync-groups/mock/%d/list-item" $acctID $syncGroupID }}"
|
||||||
"
|
hx-trigger="{{ printf "sse:accounts_%d_inventory_sync-groups_mock_%d" $acctID $syncGroupID }}"
|
||||||
|
hx-swap="morph:outerHTML"
|
||||||
|
hx-select="#{{$id}}"
|
||||||
|
hx-vals="js:{open: this.getElementsByTagName('details')[0].open}"
|
||||||
>
|
>
|
||||||
{{- define "sync-group-accordion-header" }}
|
{{- define "sync-group-accordion-header" }}
|
||||||
<h3 class="text-center">
|
<h3 class="text-center">
|
||||||
@@ -23,6 +31,7 @@
|
|||||||
|
|
||||||
{{- define "sync-group-accordion-body" }}
|
{{- define "sync-group-accordion-body" }}
|
||||||
{{- $acctID := .Identity.Account.AccountID }}
|
{{- $acctID := .Identity.Account.AccountID }}
|
||||||
|
{{- $syncGroupID := .Group.SyncGroupID }}
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -62,16 +71,30 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{{- component "button"
|
<div>
|
||||||
"Class" "mt-[1em]"
|
{{- $isBeingEditing := .Accounts.MockSyncGroupIsBeingEdited $acctID $syncGroupID }}
|
||||||
"Text" "Delete Group"
|
{{- if not $isBeingEditing }}
|
||||||
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d" $acctID .Group.SyncGroupID)
|
{{- component "button"
|
||||||
"HXSwap" "none"
|
"Class" "mt-[1em]"
|
||||||
}}
|
"Text" "Edit Group"
|
||||||
|
"HXPut" (printf "/api/accounts/%d/inventory/sync-groups/mock/editing" $acctID)
|
||||||
|
"HXVals" (printf `js:{"syncGroupID":%d}` $syncGroupID)
|
||||||
|
"HXSwap" "none"
|
||||||
|
}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- component "button"
|
||||||
|
"Class" "mt-[1em]"
|
||||||
|
"Text" "Delete Group"
|
||||||
|
"HXDelete" (printf "/api/accounts/%d/inventory/sync-groups/mock/%d" $acctID $syncGroupID)
|
||||||
|
"HXSwap" "none"
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{ component "accordion"
|
{{ component "accordion"
|
||||||
"Name" "sync-group-page"
|
"Name" "sync-group-page"
|
||||||
|
"Open" $open
|
||||||
"GroupName" "sync-group"
|
"GroupName" "sync-group"
|
||||||
"Group" $grp
|
"Group" $grp
|
||||||
"Smooth" false
|
"Smooth" false
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{{/* .HXGet | .HXPost | .HXDelete, .HXTrigger, .HXTarget, .HXSelect, .HXSwap, .HXVals, ._, .Text, .ID, .Class, .Disabled */}}
|
{{/* .HXGet | .HXPost | .HXPut | .HXDelete, .HXTrigger, .HXTarget, .HXSelect, .HXSwap, .HXVals, ._, .Text, .ID, .Class, .Disabled */}}
|
||||||
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
hx-get="{{.HXGet}}"
|
hx-get="{{.HXGet}}"
|
||||||
{{- else if .HXPost }}
|
{{- else if .HXPost }}
|
||||||
hx-post="{{.HXPost}}"
|
hx-post="{{.HXPost}}"
|
||||||
|
{{- else if .HXPut }}
|
||||||
|
hx-put="{{.HXPut}}"
|
||||||
{{- else if .HXDelete }}
|
{{- else if .HXDelete }}
|
||||||
hx-delete="{{.HXDelete}}"
|
hx-delete="{{.HXDelete}}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -39,7 +41,8 @@
|
|||||||
hx-swap="{{.HXSwap}}"
|
hx-swap="{{.HXSwap}}"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .HXVals }}
|
{{- if .HXVals }}
|
||||||
hx-vals='{{.HXVals}}'
|
{{/*hx-vals='{{.HXVals}}'*/}}
|
||||||
|
{{rawHTMLAttr (printf "hx-vals='%s'" .HXVals)}}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Disabled}}
|
{{- if .Disabled}}
|
||||||
disabled
|
disabled
|
||||||
|
|||||||
Reference in New Issue
Block a user