fizzy-cli 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/bin/fizzy +0 -0
- package/cmd/board.go +1 -1
- package/cmd/board_create.go +1 -1
- package/cmd/board_delete.go +40 -0
- package/cmd/board_delete_test.go +121 -0
- package/cmd/board_show.go +40 -0
- package/cmd/board_show_test.go +113 -0
- package/cmd/board_update.go +72 -0
- package/cmd/board_update_test.go +233 -0
- package/cmd/card_assign.go +1 -1
- package/cmd/card_close.go +1 -1
- package/cmd/card_create.go +1 -1
- package/cmd/card_delete.go +1 -1
- package/cmd/card_golden.go +1 -1
- package/cmd/card_list.go +62 -1
- package/cmd/card_list_test.go +225 -0
- package/cmd/card_not_now.go +1 -1
- package/cmd/card_reaction.go +13 -0
- package/cmd/card_reaction_create.go +46 -0
- package/cmd/card_reaction_create_test.go +148 -0
- package/cmd/card_reaction_delete.go +46 -0
- package/cmd/card_reaction_delete_test.go +112 -0
- package/cmd/card_reaction_list.go +51 -0
- package/cmd/card_reaction_list_test.go +127 -0
- package/cmd/card_reopen.go +1 -1
- package/cmd/card_tag.go +1 -1
- package/cmd/card_triage.go +1 -1
- package/cmd/card_ungolden.go +1 -1
- package/cmd/card_untriage.go +1 -1
- package/cmd/card_unwatch.go +1 -1
- package/cmd/card_update.go +1 -1
- package/cmd/card_watch.go +1 -1
- package/cmd/column_create.go +1 -1
- package/cmd/column_delete.go +40 -0
- package/cmd/column_delete_test.go +121 -0
- package/cmd/column_show.go +40 -0
- package/cmd/column_show_test.go +111 -0
- package/cmd/column_update.go +67 -0
- package/cmd/column_update_test.go +198 -0
- package/cmd/comment_create.go +1 -1
- package/cmd/comment_delete.go +1 -1
- package/cmd/comment_update.go +1 -1
- package/cmd/login.go +12 -12
- package/cmd/notification_unread.go +1 -1
- package/cmd/reaction.go +2 -2
- package/cmd/reaction_create.go +1 -1
- package/cmd/reaction_delete.go +1 -1
- package/cmd/step_create.go +1 -1
- package/cmd/step_delete.go +1 -1
- package/cmd/step_update.go +1 -1
- package/cmd/user.go +22 -0
- package/cmd/user_deactivate.go +40 -0
- package/cmd/user_deactivate_test.go +121 -0
- package/cmd/user_list.go +44 -0
- package/cmd/user_list_test.go +126 -0
- package/cmd/user_show.go +40 -0
- package/cmd/user_show_test.go +110 -0
- package/cmd/user_update.go +71 -0
- package/cmd/user_update_test.go +177 -0
- package/docs/API.md +63 -2
- package/internal/api/boards.go +34 -0
- package/internal/api/cards.go +40 -6
- package/internal/api/columns.go +63 -0
- package/internal/api/reactions.go +61 -0
- package/internal/api/types.go +17 -0
- package/internal/api/users.go +75 -0
- package/internal/ui/board_show.go +17 -0
- package/internal/ui/column_show.go +16 -0
- package/internal/ui/format.go +14 -1
- package/internal/ui/user_list.go +19 -0
- package/internal/ui/user_show.go +23 -0
- package/package.json +1 -1
package/docs/API.md
CHANGED
|
@@ -553,7 +553,8 @@ __Response:__
|
|
|
553
553
|
"created_at": "2025-12-05T19:36:35.401Z",
|
|
554
554
|
"url": "http://fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7"
|
|
555
555
|
},
|
|
556
|
-
"comments_url": "http://fizzy.localhost:3006/897362094/cards/4/comments"
|
|
556
|
+
"comments_url": "http://fizzy.localhost:3006/897362094/cards/4/comments",
|
|
557
|
+
"reactions_url": "http://fizzy.localhost:3006/897362094/cards/4/reactions"
|
|
557
558
|
},
|
|
558
559
|
]
|
|
559
560
|
```
|
|
@@ -614,6 +615,7 @@ __Response:__
|
|
|
614
615
|
"url": "http://fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7"
|
|
615
616
|
},
|
|
616
617
|
"comments_url": "http://fizzy.localhost:3006/897362094/cards/4/comments",
|
|
618
|
+
"reactions_url": "http://fizzy.localhost:3006/897362094/cards/4/reactions",
|
|
617
619
|
"steps": [
|
|
618
620
|
{
|
|
619
621
|
"id": "03f8huu0sog76g3s975963b5e",
|
|
@@ -928,7 +930,66 @@ __Response:__
|
|
|
928
930
|
|
|
929
931
|
Returns `204 No Content` on success.
|
|
930
932
|
|
|
931
|
-
## Reactions
|
|
933
|
+
## Card Reactions (Boosts)
|
|
934
|
+
|
|
935
|
+
Card reactions (also called "boosts") let users add short responses directly to cards. These are limited to 16 characters.
|
|
936
|
+
|
|
937
|
+
### `GET /:account_slug/cards/:card_number/reactions`
|
|
938
|
+
|
|
939
|
+
Returns a list of reactions on a card.
|
|
940
|
+
|
|
941
|
+
__Response:__
|
|
942
|
+
|
|
943
|
+
```json
|
|
944
|
+
[
|
|
945
|
+
{
|
|
946
|
+
"id": "03f5v9zo9qlcwwpyc0ascnikz",
|
|
947
|
+
"content": "👍",
|
|
948
|
+
"reacter": {
|
|
949
|
+
"id": "03f5v9zjw7pz8717a4no1h8a7",
|
|
950
|
+
"name": "David Heinemeier Hansson",
|
|
951
|
+
"role": "owner",
|
|
952
|
+
"active": true,
|
|
953
|
+
"email_address": "david@example.com",
|
|
954
|
+
"created_at": "2025-12-05T19:36:35.401Z",
|
|
955
|
+
"url": "http://fizzy.localhost:3006/897362094/users/03f5v9zjw7pz8717a4no1h8a7"
|
|
956
|
+
},
|
|
957
|
+
"url": "http://fizzy.localhost:3006/897362094/cards/3/reactions/03f5v9zo9qlcwwpyc0ascnikz"
|
|
958
|
+
}
|
|
959
|
+
]
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### `POST /:account_slug/cards/:card_number/reactions`
|
|
963
|
+
|
|
964
|
+
Adds a reaction (boost) to a card.
|
|
965
|
+
|
|
966
|
+
| Parameter | Type | Required | Description |
|
|
967
|
+
|-----------|------|----------|-------------|
|
|
968
|
+
| `content` | string | Yes | The reaction text (max 16 characters) |
|
|
969
|
+
|
|
970
|
+
__Request:__
|
|
971
|
+
|
|
972
|
+
```json
|
|
973
|
+
{
|
|
974
|
+
"reaction": {
|
|
975
|
+
"content": "Great 👍"
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
__Response:__
|
|
981
|
+
|
|
982
|
+
Returns `201 Created` on success.
|
|
983
|
+
|
|
984
|
+
### `DELETE /:account_slug/cards/:card_number/reactions/:reaction_id`
|
|
985
|
+
|
|
986
|
+
Removes your reaction from a card. Only the reaction creator can remove their own reactions.
|
|
987
|
+
|
|
988
|
+
__Response:__
|
|
989
|
+
|
|
990
|
+
Returns `204 No Content` on success.
|
|
991
|
+
|
|
992
|
+
## Comment Reactions
|
|
932
993
|
|
|
933
994
|
Reactions are short (16-character max) responses to comments.
|
|
934
995
|
|
package/internal/api/boards.go
CHANGED
|
@@ -57,3 +57,37 @@ func (c *Client) PostBoards(ctx context.Context, payload CreateBoardPayload) (bo
|
|
|
57
57
|
|
|
58
58
|
return true, nil
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
func (c *Client) PutBoard(ctx context.Context, boardID string, payload UpdateBoardPayload) error {
|
|
62
|
+
endpointURL := c.AccountBaseURL + "/boards/" + boardID
|
|
63
|
+
|
|
64
|
+
body := map[string]UpdateBoardPayload{"board": payload}
|
|
65
|
+
|
|
66
|
+
req, err := c.newRequest(ctx, http.MethodPut, endpointURL, body)
|
|
67
|
+
if err != nil {
|
|
68
|
+
return fmt.Errorf("failed to create update board request: %w", err)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
72
|
+
if err != nil {
|
|
73
|
+
return err
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return nil
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func (c *Client) DeleteBoard(ctx context.Context, boardID string) error {
|
|
80
|
+
endpointURL := c.AccountBaseURL + "/boards/" + boardID
|
|
81
|
+
|
|
82
|
+
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
83
|
+
if err != nil {
|
|
84
|
+
return fmt.Errorf("failed to create delete board request: %w", err)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
88
|
+
if err != nil {
|
|
89
|
+
return err
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return nil
|
|
93
|
+
}
|
package/internal/api/cards.go
CHANGED
|
@@ -14,14 +14,48 @@ func (c *Client) GetCards(ctx context.Context, filters CardFilters) ([]Card, err
|
|
|
14
14
|
return nil, fmt.Errorf("failed to create get cards request: %w", err)
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
q := req.URL.Query()
|
|
18
|
+
|
|
19
|
+
for _, boardID := range filters.BoardIDs {
|
|
20
|
+
q.Add("board_ids[]", boardID)
|
|
21
|
+
}
|
|
22
|
+
for _, tagID := range filters.TagIDs {
|
|
23
|
+
q.Add("tag_ids[]", tagID)
|
|
24
|
+
}
|
|
25
|
+
for _, assigneeID := range filters.AssigneeIDs {
|
|
26
|
+
q.Add("assignee_ids[]", assigneeID)
|
|
27
|
+
}
|
|
28
|
+
for _, creatorID := range filters.CreatorIDs {
|
|
29
|
+
q.Add("creator_ids[]", creatorID)
|
|
30
|
+
}
|
|
31
|
+
for _, closerID := range filters.CloserIDs {
|
|
32
|
+
q.Add("closer_ids[]", closerID)
|
|
33
|
+
}
|
|
34
|
+
for _, cardID := range filters.CardIDs {
|
|
35
|
+
q.Add("card_ids[]", cardID)
|
|
36
|
+
}
|
|
37
|
+
for _, term := range filters.Terms {
|
|
38
|
+
q.Add("terms[]", term)
|
|
23
39
|
}
|
|
24
40
|
|
|
41
|
+
if filters.IndexedBy != "" {
|
|
42
|
+
q.Set("indexed_by", filters.IndexedBy)
|
|
43
|
+
}
|
|
44
|
+
if filters.SortedBy != "" {
|
|
45
|
+
q.Set("sorted_by", filters.SortedBy)
|
|
46
|
+
}
|
|
47
|
+
if filters.AssignmentStatus != "" {
|
|
48
|
+
q.Set("assignment_status", filters.AssignmentStatus)
|
|
49
|
+
}
|
|
50
|
+
if filters.CreationStatus != "" {
|
|
51
|
+
q.Set("creation", filters.CreationStatus)
|
|
52
|
+
}
|
|
53
|
+
if filters.ClosureStatus != "" {
|
|
54
|
+
q.Set("closure", filters.ClosureStatus)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
req.URL.RawQuery = q.Encode()
|
|
58
|
+
|
|
25
59
|
var response []Card
|
|
26
60
|
_, err = c.decodeResponse(req, &response)
|
|
27
61
|
if err != nil {
|
package/internal/api/columns.go
CHANGED
|
@@ -27,6 +27,27 @@ func (c *Client) GetColumns(ctx context.Context) ([]Column, error) {
|
|
|
27
27
|
return response, nil
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
func (c *Client) GetColumn(ctx context.Context, columnID string) (*Column, error) {
|
|
31
|
+
if c.BoardBaseURL == "" {
|
|
32
|
+
return nil, fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
endpointURL := c.BoardBaseURL + "/columns/" + columnID
|
|
36
|
+
|
|
37
|
+
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
38
|
+
if err != nil {
|
|
39
|
+
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var response Column
|
|
43
|
+
_, err = c.decodeResponse(req, &response)
|
|
44
|
+
if err != nil {
|
|
45
|
+
return nil, err
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return &response, nil
|
|
49
|
+
}
|
|
50
|
+
|
|
30
51
|
func (c *Client) PostColumns(ctx context.Context, payload CreateColumnPayload) (bool, error) {
|
|
31
52
|
if c.BoardBaseURL == "" {
|
|
32
53
|
return false, fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
@@ -48,3 +69,45 @@ func (c *Client) PostColumns(ctx context.Context, payload CreateColumnPayload) (
|
|
|
48
69
|
|
|
49
70
|
return true, nil
|
|
50
71
|
}
|
|
72
|
+
|
|
73
|
+
func (c *Client) PutColumn(ctx context.Context, columnID string, payload UpdateColumnPayload) error {
|
|
74
|
+
if c.BoardBaseURL == "" {
|
|
75
|
+
return fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
endpointURL := c.BoardBaseURL + "/columns/" + columnID
|
|
79
|
+
|
|
80
|
+
body := map[string]UpdateColumnPayload{"column": payload}
|
|
81
|
+
|
|
82
|
+
req, err := c.newRequest(ctx, http.MethodPut, endpointURL, body)
|
|
83
|
+
if err != nil {
|
|
84
|
+
return fmt.Errorf("failed to create update column request: %w", err)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
88
|
+
if err != nil {
|
|
89
|
+
return err
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return nil
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
func (c *Client) DeleteColumn(ctx context.Context, columnID string) error {
|
|
96
|
+
if c.BoardBaseURL == "" {
|
|
97
|
+
return fmt.Errorf("please select a board first with 'fizzy use --board <board_name>'")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
endpointURL := c.BoardBaseURL + "/columns/" + columnID
|
|
101
|
+
|
|
102
|
+
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
103
|
+
if err != nil {
|
|
104
|
+
return fmt.Errorf("failed to create delete column request: %w", err)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
108
|
+
if err != nil {
|
|
109
|
+
return err
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return nil
|
|
113
|
+
}
|
|
@@ -67,3 +67,64 @@ func (c *Client) DeleteCommentReaction(ctx context.Context, cardNumber int, comm
|
|
|
67
67
|
|
|
68
68
|
return true, nil
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
func (c *Client) GetCardReactions(ctx context.Context, cardNumber int) ([]Reaction, error) {
|
|
72
|
+
endpointURL := fmt.Sprintf("%s/cards/%d/reactions", c.AccountBaseURL, cardNumber)
|
|
73
|
+
|
|
74
|
+
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
75
|
+
if err != nil {
|
|
76
|
+
return nil, fmt.Errorf("failed to create get card reactions request: %w", err)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
var response []Reaction
|
|
80
|
+
_, err = c.decodeResponse(req, &response)
|
|
81
|
+
if err != nil {
|
|
82
|
+
return nil, err
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return response, nil
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func (c *Client) PostCardReaction(ctx context.Context, cardNumber int, content string) (*Reaction, error) {
|
|
89
|
+
endpointURL := fmt.Sprintf("%s/cards/%d/reactions", c.AccountBaseURL, cardNumber)
|
|
90
|
+
|
|
91
|
+
payload := map[string]map[string]string{
|
|
92
|
+
"reaction": {"content": content},
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
req, err := c.newRequest(ctx, http.MethodPost, endpointURL, payload)
|
|
96
|
+
if err != nil {
|
|
97
|
+
return nil, fmt.Errorf("failed to create post card reaction request: %w", err)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
res, err := c.HTTPClient.Do(req)
|
|
101
|
+
if err != nil {
|
|
102
|
+
return nil, fmt.Errorf("failed to make request: %w", err)
|
|
103
|
+
}
|
|
104
|
+
defer res.Body.Close()
|
|
105
|
+
|
|
106
|
+
if res.StatusCode != http.StatusCreated {
|
|
107
|
+
body, _ := io.ReadAll(res.Body)
|
|
108
|
+
return nil, fmt.Errorf("unexpected status code %d: %s", res.StatusCode, string(body))
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// API returns 201 Created with Location header, not a response body
|
|
112
|
+
// Return a Reaction object with the content field set for reference
|
|
113
|
+
return &Reaction{Content: content}, nil
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func (c *Client) DeleteCardReaction(ctx context.Context, cardNumber int, reactionID string) (bool, error) {
|
|
117
|
+
endpointURL := fmt.Sprintf("%s/cards/%d/reactions/%s", c.AccountBaseURL, cardNumber, reactionID)
|
|
118
|
+
|
|
119
|
+
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
120
|
+
if err != nil {
|
|
121
|
+
return false, fmt.Errorf("failed to create delete card reaction request: %w", err)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
125
|
+
if err != nil {
|
|
126
|
+
return false, err
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return true, nil
|
|
130
|
+
}
|
package/internal/api/types.go
CHANGED
|
@@ -18,6 +18,13 @@ type CreateBoardPayload struct {
|
|
|
18
18
|
PublicDescription string `json:"public_description"`
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
type UpdateBoardPayload struct {
|
|
22
|
+
Name string `json:"name,omitempty"`
|
|
23
|
+
AllAccess *bool `json:"all_access,omitempty"`
|
|
24
|
+
AutoPostponePeriod *int `json:"auto_postpone_period,omitempty"`
|
|
25
|
+
PublicDescription string `json:"public_description,omitempty"`
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
type Column struct {
|
|
22
29
|
ID string `json:"id"`
|
|
23
30
|
Name string `json:"name"`
|
|
@@ -35,6 +42,11 @@ type CreateColumnPayload struct {
|
|
|
35
42
|
Color *Color `json:"color,omitempty"`
|
|
36
43
|
}
|
|
37
44
|
|
|
45
|
+
type UpdateColumnPayload struct {
|
|
46
|
+
Name string `json:"name,omitempty"`
|
|
47
|
+
Color *Color `json:"color,omitempty"`
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
type Card struct {
|
|
39
51
|
ID string `json:"id"`
|
|
40
52
|
Number int `json:"number"`
|
|
@@ -109,6 +121,11 @@ type User struct {
|
|
|
109
121
|
URL string `json:"url"`
|
|
110
122
|
}
|
|
111
123
|
|
|
124
|
+
type UpdateUserPayload struct {
|
|
125
|
+
Name string `json:"name,omitempty"`
|
|
126
|
+
Avatar string `json:"avatar,omitempty"`
|
|
127
|
+
}
|
|
128
|
+
|
|
112
129
|
type Notification struct {
|
|
113
130
|
ID string `json:"id"`
|
|
114
131
|
Read bool `json:"read"`
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
package api
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"fmt"
|
|
6
|
+
"net/http"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func (c *Client) GetUsers(ctx context.Context) ([]User, error) {
|
|
10
|
+
endpointURL := c.AccountBaseURL + "/users"
|
|
11
|
+
|
|
12
|
+
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
13
|
+
if err != nil {
|
|
14
|
+
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var response []User
|
|
18
|
+
_, err = c.decodeResponse(req, &response)
|
|
19
|
+
if err != nil {
|
|
20
|
+
return nil, err
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return response, nil
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func (c *Client) GetUser(ctx context.Context, userID string) (*User, error) {
|
|
27
|
+
endpointURL := c.AccountBaseURL + "/users/" + userID
|
|
28
|
+
|
|
29
|
+
req, err := c.newRequest(ctx, http.MethodGet, endpointURL, nil)
|
|
30
|
+
if err != nil {
|
|
31
|
+
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var response User
|
|
35
|
+
_, err = c.decodeResponse(req, &response)
|
|
36
|
+
if err != nil {
|
|
37
|
+
return nil, err
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return &response, nil
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func (c *Client) PutUser(ctx context.Context, userID string, payload UpdateUserPayload) error {
|
|
44
|
+
endpointURL := c.AccountBaseURL + "/users/" + userID
|
|
45
|
+
|
|
46
|
+
body := map[string]UpdateUserPayload{"user": payload}
|
|
47
|
+
|
|
48
|
+
req, err := c.newRequest(ctx, http.MethodPut, endpointURL, body)
|
|
49
|
+
if err != nil {
|
|
50
|
+
return fmt.Errorf("failed to create update user request: %w", err)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
54
|
+
if err != nil {
|
|
55
|
+
return err
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return nil
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
func (c *Client) DeleteUser(ctx context.Context, userID string) error {
|
|
62
|
+
endpointURL := c.AccountBaseURL + "/users/" + userID
|
|
63
|
+
|
|
64
|
+
req, err := c.newRequest(ctx, http.MethodDelete, endpointURL, nil)
|
|
65
|
+
if err != nil {
|
|
66
|
+
return fmt.Errorf("failed to create delete user request: %w", err)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_, err = c.decodeResponse(req, nil, http.StatusNoContent)
|
|
70
|
+
if err != nil {
|
|
71
|
+
return err
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return nil
|
|
75
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
|
|
7
|
+
"github.com/rogeriopvl/fizzy/internal/api"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func DisplayBoard(w io.Writer, board *api.Board) error {
|
|
11
|
+
fmt.Fprintf(w, "Board: %s\n", board.Name)
|
|
12
|
+
fmt.Fprintf(w, "ID: %s\n", board.ID)
|
|
13
|
+
fmt.Fprintf(w, "All Access: %v\n", board.AllAccess)
|
|
14
|
+
fmt.Fprintf(w, "Created At: %s\n", FormatTime(board.CreatedAt))
|
|
15
|
+
fmt.Fprintf(w, "Created By: %s\n", board.Creator.Name)
|
|
16
|
+
return nil
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
|
|
7
|
+
"github.com/rogeriopvl/fizzy/internal/api"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func DisplayColumn(w io.Writer, column *api.Column) error {
|
|
11
|
+
fmt.Fprintf(w, "Column: %s\n", column.Name)
|
|
12
|
+
fmt.Fprintf(w, "ID: %s\n", column.ID)
|
|
13
|
+
fmt.Fprintf(w, "Color: %s (%s)\n", column.Color.Name, column.Color.Value)
|
|
14
|
+
fmt.Fprintf(w, "Created At: %s\n", FormatTime(column.CreatedAt))
|
|
15
|
+
return nil
|
|
16
|
+
}
|
package/internal/ui/format.go
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
package ui
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import (
|
|
4
|
+
"github.com/charmbracelet/lipgloss"
|
|
5
|
+
"time"
|
|
6
|
+
)
|
|
4
7
|
|
|
5
8
|
// DisplayMeta returns a formatted metadata string with greyed out styling
|
|
6
9
|
func DisplayMeta(label string, value string) string {
|
|
@@ -12,3 +15,13 @@ func DisplayMeta(label string, value string) string {
|
|
|
12
15
|
func DisplayID(id string) string {
|
|
13
16
|
return DisplayMeta("id", id)
|
|
14
17
|
}
|
|
18
|
+
|
|
19
|
+
// FormatTime converts an RFC3339 timestamp string to a human-readable format.
|
|
20
|
+
// If parsing fails, returns the original string.
|
|
21
|
+
func FormatTime(timeStr string) string {
|
|
22
|
+
t, err := time.Parse(time.RFC3339, timeStr)
|
|
23
|
+
if err != nil {
|
|
24
|
+
return timeStr
|
|
25
|
+
}
|
|
26
|
+
return t.Format("2006-01-02 15:04:05")
|
|
27
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
|
|
7
|
+
"github.com/rogeriopvl/fizzy/internal/api"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func DisplayUsers(w io.Writer, users []api.User) error {
|
|
11
|
+
for _, user := range users {
|
|
12
|
+
status := "active"
|
|
13
|
+
if !user.Active {
|
|
14
|
+
status = "inactive"
|
|
15
|
+
}
|
|
16
|
+
fmt.Fprintf(w, "%s (%s) - %s [%s]\n", user.Name, user.Email, DisplayID(user.ID), status)
|
|
17
|
+
}
|
|
18
|
+
return nil
|
|
19
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
package ui
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"io"
|
|
6
|
+
|
|
7
|
+
"github.com/rogeriopvl/fizzy/internal/api"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func DisplayUser(w io.Writer, user *api.User) error {
|
|
11
|
+
status := "active"
|
|
12
|
+
if !user.Active {
|
|
13
|
+
status = "inactive"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fmt.Fprintf(w, "User: %s\n", user.Name)
|
|
17
|
+
fmt.Fprintf(w, "ID: %s\n", user.ID)
|
|
18
|
+
fmt.Fprintf(w, "Email: %s\n", user.Email)
|
|
19
|
+
fmt.Fprintf(w, "Role: %s\n", user.Role)
|
|
20
|
+
fmt.Fprintf(w, "Status: %s\n", status)
|
|
21
|
+
fmt.Fprintf(w, "Created At: %s\n", FormatTime(user.CreatedAt))
|
|
22
|
+
return nil
|
|
23
|
+
}
|