checkpoint: column repositioning implementation

This commit is contained in:
Dan Anglin 2024-01-23 23:58:04 +00:00
parent 73547c49c6
commit 4286d8fcc2
Signed by: dananglin
GPG key ID: 0C1D44CFBEE68638
2 changed files with 83 additions and 7 deletions

View file

@ -11,6 +11,7 @@ import (
bolt "go.etcd.io/bbolt"
)
// Board is probably the heart of Pelican.
type Board struct {
db *bolt.DB
}
@ -90,9 +91,7 @@ func (b *Board) StatusList() ([]Status, error) {
return statuses, nil
}
// Status returns a single status from the db.
// TODO: Add a test case that handles when a status does not exist.
// Or use in delete status case.
// Status returns a single status from the database.
func (b *Board) Status(statusID int) (Status, error) {
data, err := db.Read(b.db, db.StatusBucket, statusID)
if err != nil {
@ -116,6 +115,7 @@ func (b *Board) Status(statusID int) (Status, error) {
return status, nil
}
// StatusArgs is an argument type for creating or updating statuses.
type StatusArgs struct {
Name string
Position int
@ -198,21 +198,44 @@ func (b *Board) DeleteStatus(statusID int) error {
return fmt.Errorf("unable to delete the status from the database; %w", err)
}
if err := b.normaliseStatusesPositionValues(); err != nil {
if err := b.normaliseStatusesPositionValuesFromDatabase(); err != nil {
return fmt.Errorf("unable to normalise the statuses position values; %w", err)
}
return nil
}
// normaliseStatusesPositionValues retrieves the ordered list of statuses from the database and sets
// each status' positional value based on its position in the list.
func (b *Board) normaliseStatusesPositionValues() error {
// RepositionStatus re-positions a status on the Kanban board.
func (b *Board) RepositionStatus(currentPosition, targetPosition int) error {
statuses, err := b.StatusList()
if err != nil {
return fmt.Errorf("unable to get the list of statuses; %w", err)
}
statuses = moveAndShuffle(statuses, currentPosition, targetPosition)
if err := b.normaliseStatusesPositionValues(statuses); err != nil {
return fmt.Errorf("unable to normalise the statuses position values; %w", err)
}
return nil
}
// normaliseStatusesPositionValuesFromDatabase retrieves the ordered list of statuses from the database and sets
// each status' positional value based on its position in the list before saving the updates to the database.
func (b *Board) normaliseStatusesPositionValuesFromDatabase() error {
statuses, err := b.StatusList()
if err != nil {
return fmt.Errorf("unable to get the list of statuses; %w", err)
}
return b.normaliseStatusesPositionValues(statuses)
}
// normaliseStatusesPositionValues takes a list of statuses and sets
// each status' positional value based on its position in the list before
// saving the updates to the database.
func (b *Board) normaliseStatusesPositionValues(statuses []Status) error {
for i, status := range statuses {
updateArgs := UpdateStatusArgs{
StatusID: status.ID,
@ -230,6 +253,7 @@ func (b *Board) normaliseStatusesPositionValues() error {
return nil
}
// MoveToStatusArgs is an argument type for moving a card between statuses.
type MoveToStatusArgs struct {
CardID int
CurrentStatusID int
@ -260,6 +284,7 @@ func (b *Board) MoveToStatus(args MoveToStatusArgs) error {
return nil
}
// CardArgs is an argument type for creating or updating cards.
type CardArgs struct {
NewTitle string
NewDescription string
@ -360,6 +385,7 @@ func (b *Board) CardList(ids []int) ([]Card, error) {
return cards, nil
}
// UpdateCardArgs is an argument type for updating a card.
type UpdateCardArgs struct {
CardID int
CardArgs
@ -387,6 +413,7 @@ func (b *Board) UpdateCard(args UpdateCardArgs) error {
return nil
}
// DeleteCardArgs is an argument type for deleting a card.
type DeleteCardArgs struct {
CardID int
StatusID int

49
internal/board/shuffle.go Normal file
View file

@ -0,0 +1,49 @@
package board
type shuffleDirection int
const (
forwards shuffleDirection = iota
backwards
)
// moveAndShuffle creates a new list where the element specified at the index of the current
// position is moved to the index of the target position. Elements within the range of the
// old and new positions will then shuffle forwards or backwards in the list depending on the
// direction of the move.
// This is currently used to move specified columns forwards or backwards on the Kanban board.
// When a column changes position the other columns shuffle forward or backwards as required.
func moveAndShuffle(input []Status, currentPosition, targetPosition int) []Status {
var shuffle shuffleDirection
if targetPosition < currentPosition {
// affected elements will need to shuffle backwards if the focused
// element moves towards the beginning of the list...
shuffle = backwards
} else {
// ...or else the elements need to shuffle forwards if the focused
// element moves towards the end of the list.
shuffle = forwards
}
output := make([]Status, len(input))
for ind := range input {
switch {
case (shuffle == backwards) && (ind < targetPosition || ind > currentPosition):
output[ind] = input[ind]
case (shuffle == backwards) && (ind == currentPosition):
output[targetPosition] = input[ind]
case (shuffle == backwards):
output[ind+1] = input[ind]
case (shuffle == forwards) && (ind < currentPosition || ind > targetPosition):
output[ind] = input[ind]
case (shuffle == forwards) && (ind == currentPosition):
output[targetPosition] = input[ind]
case (shuffle == forwards):
output[ind-1] = input[ind]
}
}
return output
}