- {
- board.id ?
-
Éditer le tableau
:
-
Nouveau tableau
- }
+
+
+ {
+ board.id ?
+
Éditer le tableau
:
+ Nouveau tableau
+ }
+
+
+ {
+ board.id ?
+ :
+ null
+ }
+
+
@@ -366,8 +386,16 @@ export class EditBoardPage extends React.Component {
}
onSaveBoardClick() {
+ let { board } = this.state;
+ board = { ...board };
+ if (!board.id) board.id = uuidv4();
+ this.props.dispatch(saveBoard({...board}));
+ this.props.history.push('/');
+ }
+
+ onDeleteBoardClick() {
const { board } = this.state;
- this.props.dispatch(saveBoard(board));
+ this.props.dispatch(deleteBoard(board.id));
this.props.history.push('/');
}
diff --git a/client/src/components/HomePage/BoardCard.jsx b/client/src/components/HomePage/BoardCard.jsx
index 24b016d..461a1bb 100644
--- a/client/src/components/HomePage/BoardCard.jsx
+++ b/client/src/components/HomePage/BoardCard.jsx
@@ -26,11 +26,6 @@ export class BoardCard extends React.PureComponent {
-
-
-
-
-
diff --git a/client/src/store/actions/boards.js b/client/src/store/actions/boards.js
index 49d4fe1..0eccc97 100644
--- a/client/src/store/actions/boards.js
+++ b/client/src/store/actions/boards.js
@@ -12,4 +12,12 @@ export const SAVE_BOARD_FAILURE = "SAVE_BOARD_FAILURE";
export function saveBoard(board) {
return { type: SAVE_BOARD_REQUEST, board };
+};
+
+export const DELETE_BOARD_REQUEST = "DELETE_BOARD_REQUEST";
+export const DELETE_BOARD_SUCCESS = "DELETE_BOARD_SUCCESS";
+export const DELETE_BOARD_FAILURE = "DELETE_BOARD_FAILURE";
+
+export function deleteBoard(id) {
+ return { type: DELETE_BOARD_REQUEST, id };
};
\ No newline at end of file
diff --git a/client/src/store/reducers/boards.js b/client/src/store/reducers/boards.js
index 7202f28..5ed2752 100644
--- a/client/src/store/reducers/boards.js
+++ b/client/src/store/reducers/boards.js
@@ -16,12 +16,13 @@ export function boardsReducer(state = defaultState, action) {
}
function handleSaveBoardSuccess(state, action) {
+ const { board } = action;
return {
...state,
byID: {
...state.byID,
- [action.board.id.toString()]: {
- ...action.board,
+ [board.id]: {
+ ...board,
}
}
};
diff --git a/client/src/store/sagas/boards.js b/client/src/store/sagas/boards.js
index c2d600d..c6e8fd1 100644
--- a/client/src/store/sagas/boards.js
+++ b/client/src/store/sagas/boards.js
@@ -1,5 +1,5 @@
import { put, call } from 'redux-saga/effects';
-import { FETCH_BOARDS_SUCCESS, SAVE_BOARD_SUCCESS, SAVE_BOARD_FAILURE, FETCH_BOARDS_FAILURE } from '../actions/boards';
+import { FETCH_BOARDS_SUCCESS, SAVE_BOARD_SUCCESS, SAVE_BOARD_FAILURE, FETCH_BOARDS_FAILURE, DELETE_BOARD_FAILURE, DELETE_BOARD_SUCCESS } from '../actions/boards';
import { api } from '../../util/api';
export function* fetchBoardsSaga() {
@@ -27,3 +27,17 @@ export function* saveBoardSaga(action) {
yield put({ type: SAVE_BOARD_SUCCESS, board });
}
+
+
+export function* deleteBoardSaga(action) {
+ let { id } = action;
+
+ try {
+ board = yield call(api.deleteBoard, id)
+ } catch(error) {
+ yield put({ type: DELETE_BOARD_FAILURE, error });
+ return
+ }
+
+ yield put({ type: DELETE_BOARD_SUCCESS, id });
+}
\ No newline at end of file
diff --git a/client/src/store/sagas/root.js b/client/src/store/sagas/root.js
index e73231a..8c6b45a 100644
--- a/client/src/store/sagas/root.js
+++ b/client/src/store/sagas/root.js
@@ -1,7 +1,7 @@
import { all, takeEvery, takeLatest } from 'redux-saga/effects';
import { failuresSaga } from './failure';
-import { FETCH_BOARDS_REQUEST, SAVE_BOARD_REQUEST } from '../actions/boards';
-import { fetchBoardsSaga, saveBoardSaga } from './boards';
+import { FETCH_BOARDS_REQUEST, SAVE_BOARD_REQUEST, DELETE_BOARD_REQUEST } from '../actions/boards';
+import { fetchBoardsSaga, saveBoardSaga, deleteBoardSaga } from './boards';
import { FETCH_ISSUES_REQUEST, ADD_LABEL_REQUEST, REMOVE_LABEL_REQUEST, CREATE_ISSUE_REQUEST, CREATE_ISSUE_SUCCESS } from '../actions/issues';
import { fetchIssuesSaga, addLabelSaga, removeLabelSaga, createIssueSaga } from './issues';
import { FETCH_PROJECTS_REQUEST } from '../actions/projects';
@@ -17,6 +17,7 @@ export function* rootSaga() {
takeLatest(FETCH_BOARDS_REQUEST, fetchBoardsSaga),
takeLatest(BUILD_KANBOARD_REQUEST, buildKanboardSaga),
takeLatest(SAVE_BOARD_REQUEST, saveBoardSaga),
+ takeLatest(DELETE_BOARD_REQUEST, deleteBoardSaga),
takeLatest(FETCH_ISSUES_REQUEST, fetchIssuesSaga),
takeLatest(FETCH_PROJECTS_REQUEST, fetchProjectsSaga),
takeEvery(MOVE_CARD, moveCardSaga),
diff --git a/client/src/util/api.js b/client/src/util/api.js
index ec664f0..437c755 100644
--- a/client/src/util/api.js
+++ b/client/src/util/api.js
@@ -13,6 +13,12 @@ export class APIClient {
;
}
+ deleteBoard(id) {
+ return fetch(`/api/boards/${id}`, {
+ method: 'DELETE'
+ });
+ }
+
fetchBoards() {
return fetch(`/api/boards`)
.then(res => res.json())
diff --git a/internal/repository/repository.go b/internal/repository/repository.go
index 105bc2c..28bdf23 100644
--- a/internal/repository/repository.go
+++ b/internal/repository/repository.go
@@ -1,5 +1,13 @@
package repository
+import (
+ "github.com/pkg/errors"
+)
+
+var (
+ ErrNotFound = errors.New("not found")
+)
+
type Repository struct {
boards BoardRepository
}
diff --git a/internal/repository/storm/board.go b/internal/repository/storm/board.go
index 922bc5a..8d04e9f 100644
--- a/internal/repository/storm/board.go
+++ b/internal/repository/storm/board.go
@@ -61,6 +61,18 @@ func (r *BoardRepository) Save(board *repository.Board) error {
}
func (r *BoardRepository) Delete(id repository.BoardID) error {
+ b := &boardItem{
+ ID: string(id),
+ }
+
+ if err := r.db.DeleteStruct(b); err != nil {
+ if err == storm.ErrNotFound {
+ return repository.ErrNotFound
+ }
+
+ return errors.Wrapf(err, "could not delete board '%s'", id)
+ }
+
return nil
}
diff --git a/internal/route/board.go b/internal/route/board.go
index 39e12a3..27aabfc 100644
--- a/internal/route/board.go
+++ b/internal/route/board.go
@@ -4,6 +4,8 @@ import (
"encoding/json"
"net/http"
+ "github.com/go-chi/chi"
+
"forge.cadoles.com/wpetit/gitea-kan/internal/repository"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/middleware/container"
@@ -18,6 +20,8 @@ func serveBoards(w http.ResponseWriter, r *http.Request) {
panic(errors.Wrap(err, "could not retrieve boards list"))
}
+ w.Header().Add("Content-Type", "application/json")
+
encoder := json.NewEncoder(w)
if err := encoder.Encode(boards); err != nil {
panic(errors.Wrap(err, "could not encode boards list"))
@@ -39,8 +43,28 @@ func saveBoard(w http.ResponseWriter, r *http.Request) {
panic(errors.Wrap(err, "could not save board"))
}
+ w.Header().Add("Content-Type", "application/json")
+
encoder := json.NewEncoder(w)
if err := encoder.Encode(board); err != nil {
panic(errors.Wrap(err, "could not encode board"))
}
}
+
+func deleteBoard(w http.ResponseWriter, r *http.Request) {
+ boardID := repository.BoardID(chi.URLParam(r, "boardID"))
+
+ ctn := container.Must(r.Context())
+ repo := repository.Must(ctn)
+
+ if err := repo.Boards().Delete(boardID); err != nil {
+ if err == repository.ErrNotFound {
+ http.NotFound(w, r)
+ return
+ }
+
+ panic(err)
+ }
+
+ w.WriteHeader(http.StatusNoContent)
+}
diff --git a/internal/route/route.go b/internal/route/route.go
index c102ca3..53af29f 100644
--- a/internal/route/route.go
+++ b/internal/route/route.go
@@ -21,6 +21,7 @@ func Mount(r *chi.Mux, config *config.Config) {
r.Get("/logout", handleLogout)
r.Get("/api/boards", serveBoards)
r.Post("/api/boards", saveBoard)
+ r.Delete("/api/boards/{boardID}", deleteBoard)
r.Handle("/gitea/api/*", http.StripPrefix("/gitea", http.HandlerFunc(proxyAPIRequest)))
r.Get("/*", static.Dir(config.HTTP.PublicDir, "", html5PushStateHandler))
})