Merge branch 'develop' into dist/ubuntu/bionic/develop
This commit is contained in:
commit
5284633e7f
@ -5,6 +5,7 @@ import { ConnectedBoardPage as BoardPage } from './BoardPage/BoardPage';
|
|||||||
import { ConnectedEditBoardPage as EditBoardPage } from './BoardPage/EditBoardPage';
|
import { ConnectedEditBoardPage as EditBoardPage } from './BoardPage/EditBoardPage';
|
||||||
import { store } from '../store/store';
|
import { store } from '../store/store';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
import { logout } from '../store/actions/logout';
|
||||||
|
|
||||||
export class App extends React.Component {
|
export class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
@ -16,10 +17,9 @@ export class App extends React.Component {
|
|||||||
<Route path="/boards/new" exact component={EditBoardPage} />
|
<Route path="/boards/new" exact component={EditBoardPage} />
|
||||||
<Route path="/boards/:id" exact component={BoardPage} />
|
<Route path="/boards/:id" exact component={BoardPage} />
|
||||||
<Route path="/boards/:id/edit" exact component={EditBoardPage} />
|
<Route path="/boards/:id/edit" exact component={EditBoardPage} />
|
||||||
<Route path="/boards/:id/delete" exact component={BoardPage} />
|
|
||||||
<Route path="/logout" exact component={() => {
|
<Route path="/logout" exact component={() => {
|
||||||
window.location = "/logout";
|
this.logout();
|
||||||
return null;
|
return <Redirect to="/" />;
|
||||||
}} />
|
}} />
|
||||||
<Route component={() => <Redirect to="/" />} />
|
<Route component={() => <Redirect to="/" />} />
|
||||||
</Switch>
|
</Switch>
|
||||||
@ -27,4 +27,8 @@ export class App extends React.Component {
|
|||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
store.dispatch(logout());
|
||||||
|
}
|
||||||
}
|
}
|
@ -66,7 +66,7 @@ export class BoardPage extends React.Component {
|
|||||||
renderNewCardModal() {
|
renderNewCardModal() {
|
||||||
const { newCardModalActive, newCardLaneID } = this.state;
|
const { newCardModalActive, newCardLaneID } = this.state;
|
||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
if (!board) return null;
|
if (!board || !newCardLaneID) return null;
|
||||||
return (
|
return (
|
||||||
<Modal active={newCardModalActive}>
|
<Modal active={newCardModalActive}>
|
||||||
<div className="new-card-modal">
|
<div className="new-card-modal">
|
||||||
|
@ -2,16 +2,17 @@ import React from 'react';
|
|||||||
import { Page } from '../Page';
|
import { Page } from '../Page';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectFlagsIsLoading } from '../../store/selectors/flags';
|
import { selectFlagsIsLoading } from '../../store/selectors/flags';
|
||||||
import { fetchBoards, saveBoard } from '../../store/actions/boards';
|
import { fetchBoards, saveBoard, deleteBoard } from '../../store/actions/boards';
|
||||||
import { fetchProjects } from '../../store/actions/projects';
|
import { fetchProjects } from '../../store/actions/projects';
|
||||||
import uuidv4 from 'uuid/v4';
|
import uuidv4 from 'uuid/v4';
|
||||||
|
import { Loader } from '../Loader';
|
||||||
|
|
||||||
export class EditBoardPage extends React.Component {
|
export class EditBoardPage extends React.Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
edited: false,
|
edited: false,
|
||||||
board: {
|
board: {
|
||||||
id: uuidv4(),
|
id: "",
|
||||||
title: "",
|
title: "",
|
||||||
description: "",
|
description: "",
|
||||||
projects: [],
|
projects: [],
|
||||||
@ -42,6 +43,7 @@ export class EditBoardPage extends React.Component {
|
|||||||
this.onBoardDescriptionChange = this.onBoardAttrChange.bind(this, 'description');
|
this.onBoardDescriptionChange = this.onBoardAttrChange.bind(this, 'description');
|
||||||
this.onBoardLaneTitleChange = this.onBoardLaneAttrChange.bind(this, 'title');
|
this.onBoardLaneTitleChange = this.onBoardLaneAttrChange.bind(this, 'title');
|
||||||
this.onBoardLaneIssueLabelChange = this.onBoardLaneAttrChange.bind(this, 'issueLabel');
|
this.onBoardLaneIssueLabelChange = this.onBoardLaneAttrChange.bind(this, 'issueLabel');
|
||||||
|
this.onDeleteBoardClick = this.onDeleteBoardClick.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -50,20 +52,38 @@ export class EditBoardPage extends React.Component {
|
|||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<p>Loading...</p>
|
<Page>
|
||||||
|
<Loader></Loader>
|
||||||
|
</Page>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<div className="container is-fluid">
|
<div className="container is-fluid has-margin-top-normal">
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
<div className="column is-6 is-offset-3">
|
<div className="column is-6 is-offset-3">
|
||||||
{
|
<div className="level is-mobile">
|
||||||
board.id ?
|
<div className="level-left">
|
||||||
<h3 className="is-size-3">Éditer le tableau</h3> :
|
{
|
||||||
<h3 className="is-size-3">Nouveau tableau</h3>
|
board.id ?
|
||||||
}
|
<h3 className="is-size-3 level-item">Éditer le tableau</h3> :
|
||||||
|
<h3 className="is-size-3 level-item">Nouveau tableau</h3>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="level-right">
|
||||||
|
{
|
||||||
|
board.id ?
|
||||||
|
<button onClick={this.onDeleteBoardClick} className="level-item button is-danger">
|
||||||
|
<span className="icon">
|
||||||
|
<i className="fas fa-trash"></i>
|
||||||
|
</span>
|
||||||
|
<span>Supprimer</span>
|
||||||
|
</button> :
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<label className="label">Titre</label>
|
<label className="label">Titre</label>
|
||||||
<div className="control">
|
<div className="control">
|
||||||
@ -366,8 +386,16 @@ export class EditBoardPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onSaveBoardClick() {
|
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;
|
const { board } = this.state;
|
||||||
this.props.dispatch(saveBoard(board));
|
this.props.dispatch(deleteBoard(board.id));
|
||||||
this.props.history.push('/');
|
this.props.history.push('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
const issueURLPattern = /(^https?:\/\/([^\/]))$/i;
|
||||||
|
|
||||||
export class IssueCard extends React.PureComponent {
|
export class IssueCard extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const { card } = this.props;
|
const { card } = this.props;
|
||||||
|
const issueURLInfo = extractInfoFromIssueURL(card.issue.url);
|
||||||
|
const projectURL = `${issueURLInfo.baseURL}/${issueURLInfo.owner}/${issueURLInfo.projectName}`;
|
||||||
|
const issueURL = `${projectURL}/issues/${card.issue.number}`;
|
||||||
return (
|
return (
|
||||||
<div className="kanboard-card">
|
<div className="kanboard-card">
|
||||||
<div className="box">
|
<div className="box">
|
||||||
@ -30,14 +35,14 @@ export class IssueCard extends React.PureComponent {
|
|||||||
</div>
|
</div>
|
||||||
<div className="level is-mobile" style={{marginTop:'1rem'}}>
|
<div className="level is-mobile" style={{marginTop:'1rem'}}>
|
||||||
<div className="level-left">
|
<div className="level-left">
|
||||||
<small className="level-item"><a href="#">{card.project}</a></small>
|
<small className="level-item"><a href={projectURL}>{card.project}</a></small>
|
||||||
</div>
|
</div>
|
||||||
<div className="level-right">
|
<div className="level-right">
|
||||||
<a className="level-item" target="_blank" href={card.issue.url.replace('/api/v1/repos', '')}>
|
<a className="level-item" target="_blank" href={issueURL}>
|
||||||
<span className="icon is-small has-text-info">
|
<span className="icon is-small has-text-info">
|
||||||
<i className="fas fa-search" aria-hidden="true"></i>
|
<i className="fas fa-search" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -45,3 +50,13 @@ export class IssueCard extends React.PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractInfoFromIssueURL(issueURL) {
|
||||||
|
const pattern = /^(https?:\/\/[^\/]+)\/api\/v1\/repos\/([^\/]+)\/([^\/]+)\/.*$/;
|
||||||
|
const matches = pattern.exec(issueURL);
|
||||||
|
return {
|
||||||
|
baseURL: matches[1],
|
||||||
|
owner: matches[2],
|
||||||
|
projectName: matches[3],
|
||||||
|
};
|
||||||
|
}
|
@ -26,11 +26,6 @@ export class BoardCard extends React.PureComponent {
|
|||||||
<i className="fas fa-edit" aria-hidden="true"></i>
|
<i className="fas fa-edit" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<a className="level-item" aria-label="delete" href={`#/boards/${board.id}/delete`}>
|
|
||||||
<span className="icon is-small has-text-danger">
|
|
||||||
<i className="fas fa-trash-alt" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@ export class Navbar extends React.PureComponent {
|
|||||||
<div className="container is-fluid">
|
<div className="container is-fluid">
|
||||||
<div className="navbar-brand">
|
<div className="navbar-brand">
|
||||||
<a className="navbar-item" href="#/">
|
<a className="navbar-item" href="#/">
|
||||||
<img src="resources/logo.svg" style={{marginRight:'5px'}} />
|
<img src="resources/logo.svg" style={{marginRight:'5px',width:'28px',height:'28px'}} />
|
||||||
<h1 className="is-size-4">GenGitKan</h1>
|
<h1 className="is-size-4">GenGitKan</h1>
|
||||||
</a>
|
</a>
|
||||||
<a role="button" className="navbar-burger" aria-label="menu" aria-expanded="false">
|
<a role="button" className="navbar-burger" aria-label="menu" aria-expanded="false">
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
[data-react-beautiful-dnd-droppable] {
|
[data-react-beautiful-dnd-droppable] {
|
||||||
height: calc(100vh) !important;
|
|
||||||
min-height: calc(100vh) !important;
|
min-height: calc(100vh) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,3 +13,11 @@ export const SAVE_BOARD_FAILURE = "SAVE_BOARD_FAILURE";
|
|||||||
export function saveBoard(board) {
|
export function saveBoard(board) {
|
||||||
return { type: SAVE_BOARD_REQUEST, 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 };
|
||||||
|
};
|
@ -1,5 +1,7 @@
|
|||||||
export const LOGOUT = "LOGOUT";
|
export const LOGOUT_REQUEST = "LOGOUT_REQUEST";
|
||||||
|
export const LOGOUT_SUCCESS = "LOGOUT_SUCCESS";
|
||||||
|
export const LOGOUT_FAILURE = "LOGOUT_FAILURE";
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return { type: LOGOUT };
|
return { type: LOGOUT_REQUEST };
|
||||||
};
|
};
|
@ -16,12 +16,13 @@ export function boardsReducer(state = defaultState, action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleSaveBoardSuccess(state, action) {
|
function handleSaveBoardSuccess(state, action) {
|
||||||
|
const { board } = action;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
byID: {
|
byID: {
|
||||||
...state.byID,
|
...state.byID,
|
||||||
[action.board.id.toString()]: {
|
[board.id]: {
|
||||||
...action.board,
|
...board,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { put, call } from 'redux-saga/effects';
|
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';
|
import { api } from '../../util/api';
|
||||||
|
|
||||||
export function* fetchBoardsSaga() {
|
export function* fetchBoardsSaga() {
|
||||||
@ -27,3 +27,17 @@ export function* saveBoardSaga(action) {
|
|||||||
|
|
||||||
yield put({ type: SAVE_BOARD_SUCCESS, board });
|
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 });
|
||||||
|
}
|
@ -1,3 +1,17 @@
|
|||||||
|
import { call, put } from 'redux-saga/effects';
|
||||||
|
import { LOGOUT_FAILURE, LOGOUT_SUCCESS } from '../actions/logout';
|
||||||
|
|
||||||
export function* logoutSaga() {
|
export function* logoutSaga() {
|
||||||
window.location = '/logout';
|
try {
|
||||||
|
yield call(fetch, '/logout', { mode: 'no-cors', credentials: 'include' });
|
||||||
|
} catch(err) {
|
||||||
|
yield put({ type: LOGOUT_FAILURE, error: err });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put({ type: LOGOUT_SUCCESS });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* logoutSuccessSaga() {
|
||||||
|
window.location.reload();
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
import { all, takeEvery, takeLatest } from 'redux-saga/effects';
|
import { all, takeEvery, takeLatest } from 'redux-saga/effects';
|
||||||
import { failuresSaga } from './failure';
|
import { failuresSaga } from './failure';
|
||||||
import { FETCH_BOARDS_REQUEST, SAVE_BOARD_REQUEST } from '../actions/boards';
|
import { FETCH_BOARDS_REQUEST, SAVE_BOARD_REQUEST, DELETE_BOARD_REQUEST } from '../actions/boards';
|
||||||
import { fetchBoardsSaga, saveBoardSaga } from './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 { 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 { fetchIssuesSaga, addLabelSaga, removeLabelSaga, createIssueSaga } from './issues';
|
||||||
import { FETCH_PROJECTS_REQUEST } from '../actions/projects';
|
import { FETCH_PROJECTS_REQUEST } from '../actions/projects';
|
||||||
import { fetchProjectsSaga } from './projects';
|
import { fetchProjectsSaga } from './projects';
|
||||||
import { LOGOUT } from '../actions/logout';
|
import { LOGOUT_REQUEST, LOGOUT_SUCCESS } from '../actions/logout';
|
||||||
import { logoutSaga } from './logout';
|
import { logoutSaga, logoutSuccessSaga } from './logout';
|
||||||
import { BUILD_KANBOARD_REQUEST, MOVE_CARD } from '../actions/kanboards';
|
import { BUILD_KANBOARD_REQUEST, MOVE_CARD } from '../actions/kanboards';
|
||||||
import { buildKanboardSaga, moveCardSaga, refreshKanboardSaga } from './kanboards';
|
import { buildKanboardSaga, moveCardSaga, refreshKanboardSaga } from './kanboards';
|
||||||
|
|
||||||
@ -17,6 +17,7 @@ export function* rootSaga() {
|
|||||||
takeLatest(FETCH_BOARDS_REQUEST, fetchBoardsSaga),
|
takeLatest(FETCH_BOARDS_REQUEST, fetchBoardsSaga),
|
||||||
takeLatest(BUILD_KANBOARD_REQUEST, buildKanboardSaga),
|
takeLatest(BUILD_KANBOARD_REQUEST, buildKanboardSaga),
|
||||||
takeLatest(SAVE_BOARD_REQUEST, saveBoardSaga),
|
takeLatest(SAVE_BOARD_REQUEST, saveBoardSaga),
|
||||||
|
takeLatest(DELETE_BOARD_REQUEST, deleteBoardSaga),
|
||||||
takeLatest(FETCH_ISSUES_REQUEST, fetchIssuesSaga),
|
takeLatest(FETCH_ISSUES_REQUEST, fetchIssuesSaga),
|
||||||
takeLatest(FETCH_PROJECTS_REQUEST, fetchProjectsSaga),
|
takeLatest(FETCH_PROJECTS_REQUEST, fetchProjectsSaga),
|
||||||
takeEvery(MOVE_CARD, moveCardSaga),
|
takeEvery(MOVE_CARD, moveCardSaga),
|
||||||
@ -24,7 +25,8 @@ export function* rootSaga() {
|
|||||||
takeEvery(REMOVE_LABEL_REQUEST, removeLabelSaga),
|
takeEvery(REMOVE_LABEL_REQUEST, removeLabelSaga),
|
||||||
takeLatest(CREATE_ISSUE_REQUEST, createIssueSaga),
|
takeLatest(CREATE_ISSUE_REQUEST, createIssueSaga),
|
||||||
takeLatest(CREATE_ISSUE_SUCCESS, refreshKanboardSaga),
|
takeLatest(CREATE_ISSUE_SUCCESS, refreshKanboardSaga),
|
||||||
takeLatest(LOGOUT, logoutSaga)
|
takeLatest(LOGOUT_REQUEST, logoutSaga),
|
||||||
|
takeLatest(LOGOUT_SUCCESS, logoutSuccessSaga)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ export function selectBoardByUserProjects(boardsByID, projectsByName) {
|
|||||||
const userProjects = Object.keys(projectsByName);
|
const userProjects = Object.keys(projectsByName);
|
||||||
return Object.keys(boardsByID).reduce((filteredBoardsByID, boardID) => {
|
return Object.keys(boardsByID).reduce((filteredBoardsByID, boardID) => {
|
||||||
const board = boardsByID[boardID];
|
const board = boardsByID[boardID];
|
||||||
const hasProject = board.projects.some(p => userProjects.indexOf(p) !== -1);
|
const hasProject = board.projects.length === 0 || board.projects.some(p => userProjects.indexOf(p) !== -1);
|
||||||
if (hasProject) {
|
if (hasProject) {
|
||||||
filteredBoardsByID[boardID] = board;
|
filteredBoardsByID[boardID] = board;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,12 @@ export class APIClient {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteBoard(id) {
|
||||||
|
return fetch(`/api/boards/${id}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fetchBoards() {
|
fetchBoards() {
|
||||||
return fetch(`/api/boards`)
|
return fetch(`/api/boards`)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
package repository
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNotFound = errors.New("not found")
|
||||||
|
)
|
||||||
|
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
boards BoardRepository
|
boards BoardRepository
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,18 @@ func (r *BoardRepository) Save(board *repository.Board) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *BoardRepository) Delete(id repository.BoardID) 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
|
||||||
"forge.cadoles.com/wpetit/gitea-kan/internal/repository"
|
"forge.cadoles.com/wpetit/gitea-kan/internal/repository"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gitlab.com/wpetit/goweb/middleware/container"
|
"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"))
|
panic(errors.Wrap(err, "could not retrieve boards list"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
encoder := json.NewEncoder(w)
|
||||||
if err := encoder.Encode(boards); err != nil {
|
if err := encoder.Encode(boards); err != nil {
|
||||||
panic(errors.Wrap(err, "could not encode boards list"))
|
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"))
|
panic(errors.Wrap(err, "could not save board"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
encoder := json.NewEncoder(w)
|
||||||
if err := encoder.Encode(board); err != nil {
|
if err := encoder.Encode(board); err != nil {
|
||||||
panic(errors.Wrap(err, "could not encode board"))
|
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)
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ func Mount(r *chi.Mux, config *config.Config) {
|
|||||||
r.Get("/logout", handleLogout)
|
r.Get("/logout", handleLogout)
|
||||||
r.Get("/api/boards", serveBoards)
|
r.Get("/api/boards", serveBoards)
|
||||||
r.Post("/api/boards", saveBoard)
|
r.Post("/api/boards", saveBoard)
|
||||||
|
r.Delete("/api/boards/{boardID}", deleteBoard)
|
||||||
r.Handle("/gitea/api/*", http.StripPrefix("/gitea", http.HandlerFunc(proxyAPIRequest)))
|
r.Handle("/gitea/api/*", http.StripPrefix("/gitea", http.HandlerFunc(proxyAPIRequest)))
|
||||||
r.Get("/*", static.Dir(config.HTTP.PublicDir, "", html5PushStateHandler))
|
r.Get("/*", static.Dir(config.HTTP.PublicDir, "", html5PushStateHandler))
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user