Compare commits
17 Commits
6ffb2915bf
...
pkg/dev/ub
Author | SHA1 | Date | |
---|---|---|---|
59dcb4c18a | |||
61ef77cf16 | |||
acde7436da | |||
b3d458ebac | |||
5284633e7f | |||
5c77f22c26 | |||
204d6869ec | |||
35683a4584 | |||
64dd215038 | |||
d8192e6953 | |||
4d3175a25e | |||
ca7b8aac47 | |||
971bf25f16 | |||
a2ab012c5f | |||
fb815c4d83 | |||
88a0a5bebe | |||
f54b579ae3 |
@ -9,7 +9,6 @@
|
|||||||
### Procédure
|
### Procédure
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd client && npm install # Installation des dépendances client
|
|
||||||
make watch # Surveiller les modifications sur le sources et compiler/démarrer le serveur
|
make watch # Surveiller les modifications sur le sources et compiler/démarrer le serveur
|
||||||
```
|
```
|
||||||
|
|
||||||
|
9933
client/package-lock.json
generated
9933
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -27,9 +27,9 @@
|
|||||||
"@fortawesome/fontawesome-free": "^5.11.2",
|
"@fortawesome/fontawesome-free": "^5.11.2",
|
||||||
"@types/node": "^13.13.4",
|
"@types/node": "^13.13.4",
|
||||||
"@types/react-dom": "^16.9.7",
|
"@types/react-dom": "^16.9.7",
|
||||||
"@types/react-redux": "^7.1.7",
|
|
||||||
"@types/react-router-dom": "^5.1.5",
|
"@types/react-router-dom": "^5.1.5",
|
||||||
"@types/uuid": "^7.0.3",
|
"@types/uuid": "^7.0.3",
|
||||||
|
"@types/react-redux": "^7.1.7",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"css-loader": "^1.0.1",
|
"css-loader": "^1.0.1",
|
||||||
"extract-loader": "^3.1.0",
|
"extract-loader": "^3.1.0",
|
||||||
@ -42,15 +42,14 @@
|
|||||||
"resolve-url-loader": "^3.0.0",
|
"resolve-url-loader": "^3.0.0",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"ts-loader": "^7.0.2",
|
|
||||||
"webpack": "^4.25.0",
|
"webpack": "^4.25.0",
|
||||||
"webpack-cleanup-plugin": "^0.5.1",
|
"webpack-cleanup-plugin": "^0.5.1",
|
||||||
"webpack-cli": "^3.1.2"
|
"webpack-cli": "^3.1.2",
|
||||||
|
"ts-loader": "^7.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lourenci/react-kanban": "^2.0.0",
|
"@lourenci/react-kanban": "^0.15.0",
|
||||||
"bulma": "^0.7.2",
|
"bulma": "^0.7.2",
|
||||||
"bulma-switch": "^2.0.0",
|
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-redux": "^7.1.3",
|
"react-redux": "^7.1.3",
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import { Page } from '../Page';
|
import { Page } from '../Page';
|
||||||
import { connect, DispatchProp } from 'react-redux';
|
import { connect, DispatchProp } from 'react-redux';
|
||||||
import Board, { addColumn } from '@lourenci/react-kanban';
|
import Board from '@lourenci/react-kanban';
|
||||||
import { fetchBoards } from '../../store/actions/boards';
|
import { fetchBoards } from '../../store/actions/boards';
|
||||||
import { createIssue, fetchIssues } from '../../store/actions/issues';
|
import { createIssue } from '../../store/actions/issues';
|
||||||
import { buildKanboard, moveCard } from '../../store/actions/kanboards';
|
import { buildKanboard, moveCard } from '../../store/actions/kanboards';
|
||||||
import { Loader } from '../Loader';
|
import { Loader } from '../Loader';
|
||||||
import { IssueCard } from './IssueCard';
|
import { IssueCard } from './IssueCard';
|
||||||
import { Modal } from '../Modal';
|
import { Modal } from '../Modal';
|
||||||
import { fetchProjectMilestones } from '../../store/actions/projects';
|
|
||||||
|
|
||||||
export interface BoardPageProps extends DispatchProp {
|
export interface BoardPageProps extends DispatchProp {
|
||||||
board: any
|
board: any
|
||||||
kanboard: any
|
kanboard: any
|
||||||
milestones: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BoardPage extends React.Component<BoardPageProps> {
|
export class BoardPage extends React.Component<BoardPageProps> {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
@ -25,10 +22,7 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
title: "",
|
title: "",
|
||||||
body: "",
|
body: "",
|
||||||
project: ""
|
project: ""
|
||||||
},
|
}
|
||||||
compactMode: true,
|
|
||||||
hasError: false,
|
|
||||||
selectedMilestone: "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewCardTitleChange: (evt: any) => void;
|
onNewCardTitleChange: (evt: any) => void;
|
||||||
@ -46,104 +40,41 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
this.onNewCardSaveClick = this.onNewCardSaveClick.bind(this);
|
this.onNewCardSaveClick = this.onNewCardSaveClick.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidCatch(error, errorInfo) {
|
|
||||||
// You can also log the error to an error reporting service
|
|
||||||
console.error(error, errorInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMilestonesChange(e: any) {
|
|
||||||
console.log("EVT VALUE", e.target.value);
|
|
||||||
let m = (e.target as HTMLInputElement).value;
|
|
||||||
this.setState(state => ({ ...state, selectedMilestone: m }), this.requestBuildKanboard);
|
|
||||||
//this.requestBuildKanboard();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
return (
|
return (
|
||||||
<Page title={`${board ? (board.title + ' - ') : ''}GenGitKan`}>
|
<Page title={`${board ? (board.title + ' - ') : ''}GenGitKan`}>
|
||||||
{this.renderBoard()}
|
<div className="container is-fluid">
|
||||||
|
{this.renderBoard()}
|
||||||
|
</div>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBoard() {
|
renderBoard() {
|
||||||
const { kanboard, board, milestones } = this.props;
|
const { kanboard } = this.props;
|
||||||
|
|
||||||
if (!kanboard) {
|
if (!kanboard) {
|
||||||
return <Loader></Loader>
|
return <Loader></Loader>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<div className="kanboard-container is-fullheight">
|
||||||
<nav className="navbar is-light">
|
<Board disableLaneDrag={true}
|
||||||
<div className="container is-fluid">
|
renderCard={this.renderCard}
|
||||||
<div className="navbar-start">
|
renderLaneHeader={this.renderLaneHeader}
|
||||||
<div className="navbar-item">
|
onCardDragEnd={this.onCardDragEnd.bind(this)}>
|
||||||
{board.title}
|
{kanboard}
|
||||||
</div>
|
</Board>
|
||||||
</div>
|
{ this.renderNewCardModal() }
|
||||||
<div className="navbar-end">
|
</div>
|
||||||
<div className="navbar-item">
|
|
||||||
<div className="select">
|
|
||||||
<select onChange={this.handleMilestonesChange.bind(this)}>
|
|
||||||
<option value="">Sélectionner un jalon</option>
|
|
||||||
{
|
|
||||||
milestones.length > 0 ? milestones.map((k: any) => {
|
|
||||||
return (
|
|
||||||
<option value={k.title} key={k.id}>{k.title}</option>
|
|
||||||
)
|
|
||||||
}) : ""
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="navbar-item">
|
|
||||||
|
|
||||||
<div className="field">
|
|
||||||
|
|
||||||
<input id="compactMode"
|
|
||||||
checked={this.state.compactMode}
|
|
||||||
onChange={this.onCompactModeChange.bind(this)}
|
|
||||||
type="checkbox"
|
|
||||||
className="switch is-outlined is-success"
|
|
||||||
name="compactMode"
|
|
||||||
/>
|
|
||||||
<label htmlFor="compactMode">Mode compact</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a href={`#/boards/${board.id}/edit`} className="navbar-item">
|
|
||||||
<span className="icon">
|
|
||||||
<i className="fa fa-edit fa-fw"></i>
|
|
||||||
</span>
|
|
||||||
<span>Modifier le tableau</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div className="container is-fluid">
|
|
||||||
<div className="kanboard-container is-fullheight">
|
|
||||||
<Board
|
|
||||||
renderCard={this.renderCard.bind(this)}
|
|
||||||
renderColumnHeader={this.renderLaneHeader.bind(this)}
|
|
||||||
onCardDragEnd={this.onCardDragEnd.bind(this)}
|
|
||||||
disableColumnDrag={true}
|
|
||||||
>
|
|
||||||
{kanboard}
|
|
||||||
</Board>
|
|
||||||
{this.renderNewCardModal()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNewCardModal() {
|
renderNewCardModal() {
|
||||||
const { newCardModalActive, newCardLaneID } = this.state;
|
const { newCardModalActive, newCardLaneID } = this.state;
|
||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
if (!board || newCardLaneID === undefined) 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">
|
||||||
@ -155,17 +86,17 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
<div className="message-body">
|
<div className="message-body">
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<div className="control">
|
<div className="control">
|
||||||
<input className="input is-medium" type="text"
|
<input className="input is-medium" type="text"
|
||||||
placeholder="Titre de votre ticket..."
|
placeholder="Titre de votre ticket..."
|
||||||
value={this.state.newCard.title}
|
value={this.state.newCard.title}
|
||||||
onChange={this.onNewCardTitleChange} />
|
onChange={this.onNewCardTitleChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="field">
|
<div className="field">
|
||||||
<div className="control">
|
<div className="control">
|
||||||
<textarea className="textarea"
|
<textarea className="textarea"
|
||||||
placeholder="Description du nouveau ticket..."
|
placeholder="Description du nouveau ticket..."
|
||||||
value={this.state.newCard.body}
|
value={this.state.newCard.body}
|
||||||
onChange={this.onNewCardBodyChange}
|
onChange={this.onNewCardBodyChange}
|
||||||
rows={10}>
|
rows={10}>
|
||||||
</textarea>
|
</textarea>
|
||||||
@ -175,7 +106,7 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
<div className="control is-expanded">
|
<div className="control is-expanded">
|
||||||
<div className="select is-fullwidth">
|
<div className="select is-fullwidth">
|
||||||
<select
|
<select
|
||||||
value={this.state.newCard.project}
|
value={this.state.newCard.project}
|
||||||
onChange={this.onNewCardProjectChange}>
|
onChange={this.onNewCardProjectChange}>
|
||||||
{
|
{
|
||||||
board.projects.map((p: any, i: number) => {
|
board.projects.map((p: any, i: number) => {
|
||||||
@ -188,7 +119,7 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
</div>
|
</div>
|
||||||
<div className="field is-grouped is-grouped-right">
|
<div className="field is-grouped is-grouped-right">
|
||||||
<p className="control">
|
<p className="control">
|
||||||
<a className="button is-light"
|
<a className="button is-light"
|
||||||
onClick={this.onNewCardCloseClick}>
|
onClick={this.onNewCardCloseClick}>
|
||||||
Annuler
|
Annuler
|
||||||
</a>
|
</a>
|
||||||
@ -208,7 +139,7 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderCard(card: any) {
|
renderCard(card: any) {
|
||||||
return <IssueCard compact={this.state.compactMode} card={card} />;
|
return <IssueCard card={card} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLaneHeader(lane: any) {
|
renderLaneHeader(lane: any) {
|
||||||
@ -216,49 +147,28 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
<div className="kanboard-lane">
|
<div className="kanboard-lane">
|
||||||
<div className="level">
|
<div className="level">
|
||||||
<div className="level-left">
|
<div className="level-left">
|
||||||
<div className="level-item">
|
<h3 className="level-item is-size-3">{lane.title}</h3>
|
||||||
<span className="tag is-primary is-light is-normal">{lane.cards.length}</span>
|
|
||||||
</div>
|
|
||||||
<button className="button is-light level-item is-small expand"
|
|
||||||
onClick={this.onMinimizeColumn}>
|
|
||||||
<span className="icon">
|
|
||||||
<i className="fas fa-chevron-right" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<h3 className="level-item is-size-5">
|
|
||||||
{lane.title}
|
|
||||||
</h3>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="level-right is-show-expand">
|
<div className="level-right">
|
||||||
<button className="button is-light level-item is-small"
|
<button className="button is-light level-item is-medium"
|
||||||
onClick={this.onNewCardClick.bind(this, lane.id)}>
|
onClick={this.onNewCardClick.bind(this, lane.id)}>
|
||||||
<span className="icon">
|
<span className="icon">
|
||||||
<i className="fas fa-plus" aria-hidden="true"></i>
|
<i className="fas fa-plus" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button className="button is-light level-item is-small"
|
|
||||||
onClick={this.onMinimizeColumn}>
|
|
||||||
<span className="icon">
|
|
||||||
<i className="fas fa-chevron-left" aria-hidden="true"></i>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onMinimizeColumn(e: any) {
|
onCardDragEnd(source: any, dest: any) {
|
||||||
e.currentTarget.closest('.react-kanban-column').classList.toggle('minimized');
|
|
||||||
}
|
|
||||||
|
|
||||||
onCardDragEnd(card: any, source: any, dest: any) {
|
|
||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
this.props.dispatch(moveCard(
|
this.props.dispatch(moveCard(
|
||||||
board.id,
|
board.id,
|
||||||
source.fromColumnId,
|
source.fromLaneId,
|
||||||
source.fromPosition,
|
source.fromPosition,
|
||||||
dest.toColumnId,
|
dest.toLaneId,
|
||||||
dest.toPosition
|
dest.toPosition
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -275,8 +185,8 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
|
|
||||||
onNewCardClick(laneID: string) {
|
onNewCardClick(laneID: string) {
|
||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
this.setState({
|
this.setState({
|
||||||
newCardModalActive: true,
|
newCardModalActive: true,
|
||||||
newCardLaneID: laneID,
|
newCardLaneID: laneID,
|
||||||
newCard: {
|
newCard: {
|
||||||
title: "",
|
title: "",
|
||||||
@ -308,9 +218,9 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
this.setState({ newCardModalActive: false });
|
this.setState({ newCardModalActive: false });
|
||||||
this.props.dispatch(createIssue(
|
this.props.dispatch(createIssue(
|
||||||
newCard.project,
|
newCard.project,
|
||||||
newCard.title,
|
newCard.title,
|
||||||
newCard.body,
|
newCard.body,
|
||||||
board.lanes[newCardLaneID].issueLabel
|
board.lanes[newCardLaneID].issueLabel
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -325,25 +235,16 @@ export class BoardPage extends React.Component<BoardPageProps> {
|
|||||||
|
|
||||||
requestBuildKanboard() {
|
requestBuildKanboard() {
|
||||||
const { board } = this.props;
|
const { board } = this.props;
|
||||||
const { selectedMilestone } = this.state;
|
|
||||||
console.log("SELECTED MILESTONE", selectedMilestone)
|
|
||||||
if (!board) return;
|
if (!board) return;
|
||||||
this.props.dispatch(fetchProjectMilestones(board.projects[0]));
|
this.props.dispatch(buildKanboard(board));
|
||||||
this.props.dispatch(buildKanboard(board, selectedMilestone));
|
|
||||||
}
|
|
||||||
|
|
||||||
onCompactModeChange(evt: React.ChangeEvent) {
|
|
||||||
const checked = (evt.currentTarget as HTMLInputElement).checked;
|
|
||||||
this.setState(state => ({ ...state, compactMode: checked }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConnectedBoardPage = connect(function (state: any, props: any) {
|
export const ConnectedBoardPage = connect(function(state: any, props: any) {
|
||||||
const boardID = props.match.params.id;
|
const boardID = props.match.params.id;
|
||||||
return {
|
return {
|
||||||
board: state.boards.byID[boardID],
|
board: state.boards.byID[boardID],
|
||||||
kanboard: state.kanboards.byID[boardID],
|
kanboard: state.kanboards.byID[boardID]
|
||||||
milestones: state.projects.milestones
|
|
||||||
};
|
};
|
||||||
})(BoardPage);
|
})(BoardPage);
|
@ -1,63 +1,50 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { KanboardCard } from '../../types/kanboard';
|
|
||||||
|
|
||||||
export interface IssueCardProps {
|
export interface IssueCardProps {
|
||||||
card: KanboardCard
|
card: any
|
||||||
compact: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class IssueCard extends React.PureComponent<IssueCardProps> {
|
export class IssueCard extends React.PureComponent<IssueCardProps> {
|
||||||
render() {
|
render() {
|
||||||
|
const { card } = this.props;
|
||||||
const { card, compact } = this.props;
|
|
||||||
const issueURLInfo = extractInfoFromIssueURL(card.issue.url);
|
const issueURLInfo = extractInfoFromIssueURL(card.issue.url);
|
||||||
const projectURL = `${issueURLInfo.baseURL}/${issueURLInfo.owner}/${issueURLInfo.projectName}`;
|
const projectURL = `${issueURLInfo.baseURL}/${issueURLInfo.owner}/${issueURLInfo.projectName}`;
|
||||||
const issueURL = `${projectURL}/issues/${card.issue.number}`;
|
const issueURL = `${projectURL}/issues/${card.issue.number}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="kanboard-card">
|
<div className="kanboard-card">
|
||||||
<div className="box has-padding-small is-radiusless">
|
<div className="box">
|
||||||
<div className="media">
|
<div className="media">
|
||||||
|
{
|
||||||
|
card.issue.assignee ?
|
||||||
|
<div className="media-left">
|
||||||
|
<figure className="image is-64x64">
|
||||||
|
<img src={card.issue.assignee.avatar_url} alt="Image" />
|
||||||
|
</figure>
|
||||||
|
<small>{`@${card.issue.assignee.login}`}</small>
|
||||||
|
</div>
|
||||||
|
: null
|
||||||
|
}
|
||||||
<div className="media-content">
|
<div className="media-content">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{ !compact &&
|
<p>
|
||||||
<nav className="level">
|
<strong>{`#${card.issue.number}`}</strong>
|
||||||
<div className="level-left">
|
{ card.issue.milestone ? <small>{`- ${card.issue.milestone.title}`}</small> : null }
|
||||||
<div className="level-item">
|
<br />
|
||||||
<a target="_blank" href={issueURL}><strong>{`#${card.issue.number}`}</strong></a>
|
<span className="is-size-6">{card.issue.title}</span>
|
||||||
</div>
|
</p>
|
||||||
{ !compact &&
|
|
||||||
<div className="level-item">
|
|
||||||
<a target="_blank" href={projectURL}>{card.project}</a>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div className="level-right">
|
|
||||||
{
|
|
||||||
card.issue.assignee && !compact ?
|
|
||||||
<div className="level-item">
|
|
||||||
<small>{`@${card.issue.assignee.login}`}</small>
|
|
||||||
</div>
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
}
|
|
||||||
{ compact &&
|
|
||||||
<a target="_blank" className="mr-1" href={issueURL}><strong>{`#${card.issue.number}`}</strong></a>
|
|
||||||
}
|
|
||||||
<span>{card.issue.title ? card.issue.title : ''}</span>
|
|
||||||
</div>
|
</div>
|
||||||
{ !compact &&
|
</div>
|
||||||
<nav className="level">
|
</div>
|
||||||
<div className="level-left"></div>
|
<div className="level is-mobile" style={{marginTop:'1rem'}}>
|
||||||
<div className="level-right">
|
<div className="level-left">
|
||||||
<div className="level-item is-size-7">
|
<small className="level-item"><a href={projectURL}>{card.project}</a></small>
|
||||||
{card.issue.milestone ? card.issue.milestone.title : ''}
|
</div>
|
||||||
</div>
|
<div className="level-right">
|
||||||
</div>
|
<a className="level-item" target="_blank" href={issueURL}>
|
||||||
</nav>
|
<span className="icon is-small has-text-info">
|
||||||
}
|
<i className="fas fa-search" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
@import 'bulma/bulma.sass';
|
@import 'bulma/bulma.sass';
|
||||||
@import '../../node_modules/@lourenci/react-kanban/dist/styles.css';
|
|
||||||
@import 'bulma-switch/dist/css/bulma-switch.sass';
|
|
||||||
@import '_base.scss';
|
@import '_base.scss';
|
||||||
@import '_loader.scss';
|
@import '_loader.scss';
|
||||||
@import '_kanboard.scss';
|
@import '_kanboard.scss';
|
@ -11,15 +11,7 @@ html, body {
|
|||||||
margin-top: $size-normal;
|
margin-top: $size-normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-padding-small {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
|
||||||
|
|
||||||
.mr-1 {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
}
|
@ -44,12 +44,6 @@
|
|||||||
|
|
||||||
.kanboard-lane {
|
.kanboard-lane {
|
||||||
margin-bottom: $size-small;
|
margin-bottom: $size-small;
|
||||||
background: $white;
|
|
||||||
top: 0;
|
|
||||||
|
|
||||||
.expand {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,142 +51,4 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 50% !important;
|
width: 50% !important;
|
||||||
}
|
|
||||||
|
|
||||||
.react-kanban-board {
|
|
||||||
max-height: calc(100vh - calc(52px * 2));
|
|
||||||
overflow: hidden;
|
|
||||||
overflow-x: scroll;
|
|
||||||
|
|
||||||
scrollbar-color: $grey-lighter, #f1f1f1;
|
|
||||||
scrollbar-width: 5px;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 5px;
|
|
||||||
height: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Track */
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: #f1f1f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle */
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: $grey-lighter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle on hover */
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: $green;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-kanban-column {
|
|
||||||
transition: width ease .2s;
|
|
||||||
max-width: 305px;
|
|
||||||
min-width: 305px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
max-height: 100%;
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: scroll;
|
|
||||||
|
|
||||||
scrollbar-color: $grey-lighter, #f1f1f1;
|
|
||||||
scrollbar-width: 5px;
|
|
||||||
|
|
||||||
.kanboard-card {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.minimized {
|
|
||||||
max-width: 70px;
|
|
||||||
min-width: 70px;
|
|
||||||
|
|
||||||
writing-mode: vertical-rl;
|
|
||||||
text-orientation: sideways-right;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.level-item {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.level-left {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.level-right.is-show-expand {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kanboard-lane {
|
|
||||||
/*margin-right: -1em;*/
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: .5em;
|
|
||||||
/*margin-right: -.5em;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
writing-mode: horizontal-tb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expand {
|
|
||||||
display: block !important;
|
|
||||||
margin-top: .5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.kanboard-card {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Track */
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: #f1f1f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle */
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: $grey-lighter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle on hover */
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: $green;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-kanban-card__title {
|
|
||||||
position: sticky;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-kanban-column {
|
|
||||||
background: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.kanboard-card {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.level {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.level-item {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -2,8 +2,8 @@ export const FETCH_ISSUES_REQUEST = "FETCH_ISSUES_REQUEST";
|
|||||||
export const FETCH_ISSUES_SUCCESS = "FETCH_ISSUES_SUCCESS";
|
export const FETCH_ISSUES_SUCCESS = "FETCH_ISSUES_SUCCESS";
|
||||||
export const FETCH_ISSUES_FAILURE = "FETCH_ISSUES_FAILURE";
|
export const FETCH_ISSUES_FAILURE = "FETCH_ISSUES_FAILURE";
|
||||||
|
|
||||||
export function fetchIssues(project: any, milestones: string) {
|
export function fetchIssues(project: any) {
|
||||||
return { type: FETCH_ISSUES_REQUEST, project, milestones };
|
return { type: FETCH_ISSUES_REQUEST, project };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ADD_LABEL_REQUEST = "ADD_LABEL_REQUEST";
|
export const ADD_LABEL_REQUEST = "ADD_LABEL_REQUEST";
|
||||||
|
@ -2,8 +2,8 @@ export const BUILD_KANBOARD_REQUEST = "BUILD_KANBOARD_REQUEST";
|
|||||||
export const BUILD_KANBOARD_SUCCESS = "BUILD_KANBOARD_SUCCESS";
|
export const BUILD_KANBOARD_SUCCESS = "BUILD_KANBOARD_SUCCESS";
|
||||||
export const BUILD_KANBOARD_FAILURE = "BUILD_KANBOARD_FAILURE";
|
export const BUILD_KANBOARD_FAILURE = "BUILD_KANBOARD_FAILURE";
|
||||||
|
|
||||||
export function buildKanboard(board: string, milestones: string) {
|
export function buildKanboard(board: string) {
|
||||||
return { type: BUILD_KANBOARD_REQUEST, board, milestones };
|
return { type: BUILD_KANBOARD_REQUEST, board };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MOVE_CARD = "MOVE_CARD";
|
export const MOVE_CARD = "MOVE_CARD";
|
||||||
|
@ -2,14 +2,6 @@ export const FETCH_PROJECTS_REQUEST = "FETCH_PROJECTS_REQUEST";
|
|||||||
export const FETCH_PROJECTS_SUCCESS = "FETCH_PROJECTS_SUCCESS";
|
export const FETCH_PROJECTS_SUCCESS = "FETCH_PROJECTS_SUCCESS";
|
||||||
export const FETCH_PROJECTS_FAILURE = "FETCH_PROJECTS_FAILURE";
|
export const FETCH_PROJECTS_FAILURE = "FETCH_PROJECTS_FAILURE";
|
||||||
|
|
||||||
export const FETCH_PROJECT_MILESTONES_REQUEST = "FETCH_PROJECTS_MILESTONES_REQUEST";
|
|
||||||
export const FETCH_PROJECT_MILESTONES_SUCCESS = "FETCH_PROJECTS_MILESTONES_SUCCESS";
|
|
||||||
export const FETCH_PROJECT_MILESTONES_FAILURE = "FETCH_PROJECTS_MILESTONES_FAILURE";
|
|
||||||
|
|
||||||
export function fetchProjects() {
|
export function fetchProjects() {
|
||||||
return { type: FETCH_PROJECTS_REQUEST };
|
return { type: FETCH_PROJECTS_REQUEST };
|
||||||
};
|
|
||||||
|
|
||||||
export function fetchProjectMilestones(project: any) {
|
|
||||||
return { type: FETCH_PROJECT_MILESTONES_REQUEST, project };
|
|
||||||
};
|
};
|
@ -37,22 +37,22 @@ function handleMoveCard(state: any, action: any) {
|
|||||||
|
|
||||||
const kanboard = state.byID[boardID];
|
const kanboard = state.byID[boardID];
|
||||||
|
|
||||||
const columns = [ ...kanboard.columns ];
|
const lanes = [ ...kanboard.lanes ];
|
||||||
const fromLane = columns[fromLaneID];
|
const fromLane = lanes[fromLaneID];
|
||||||
const toLane = columns[toLaneID];
|
const toLane = lanes[toLaneID];
|
||||||
const card = fromLane.cards[fromPosition];
|
const card = fromLane.cards[fromPosition];
|
||||||
|
|
||||||
const fromCards = [ ...fromLane.cards ];
|
const fromCards = [ ...fromLane.cards ];
|
||||||
if (fromLaneID !== toLaneID) {
|
if (fromLaneID !== toLaneID) {
|
||||||
fromCards.splice(fromPosition, 1);
|
fromCards.splice(fromPosition, 1);
|
||||||
columns[fromLaneID] = {
|
lanes[fromLaneID] = {
|
||||||
...fromLane,
|
...fromLane,
|
||||||
cards: fromCards,
|
cards: fromCards,
|
||||||
};
|
};
|
||||||
|
|
||||||
const toCards = [ ...toLane.cards ];
|
const toCards = [ ...toLane.cards ];
|
||||||
toCards.splice(toPosition, 0, card);
|
toCards.splice(toPosition, 0, card);
|
||||||
columns[toLaneID] = {
|
lanes[toLaneID] = {
|
||||||
...toLane,
|
...toLane,
|
||||||
cards: toCards,
|
cards: toCards,
|
||||||
};
|
};
|
||||||
@ -67,7 +67,7 @@ function handleMoveCard(state: any, action: any) {
|
|||||||
...state.byID,
|
...state.byID,
|
||||||
[boardID]: {
|
[boardID]: {
|
||||||
...state.byID[boardID],
|
...state.byID[boardID],
|
||||||
columns,
|
lanes,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,18 +1,13 @@
|
|||||||
import { FETCH_PROJECTS_SUCCESS, FETCH_PROJECT_MILESTONES_SUCCESS } from "../actions/projects";
|
import { FETCH_PROJECTS_SUCCESS } from "../actions/projects";
|
||||||
|
|
||||||
export const defaultState = {
|
export const defaultState = {
|
||||||
byName: {},
|
byName: {},
|
||||||
milestones: ""
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function projectsReducer(state = defaultState, action: any) {
|
export function projectsReducer(state = defaultState, action: any) {
|
||||||
switch (action.type) {
|
switch(action.type) {
|
||||||
case FETCH_PROJECTS_SUCCESS:
|
case FETCH_PROJECTS_SUCCESS:
|
||||||
return handleFetchProjectsSuccess(state, action);
|
return handleFetchProjectsSuccess(state, action);
|
||||||
|
|
||||||
case FETCH_PROJECT_MILESTONES_SUCCESS:
|
|
||||||
return handleFetchProjectMilestonesSuccess(state, action);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -29,11 +24,4 @@ function handleFetchProjectsSuccess(state: any, action: any) {
|
|||||||
...projectsByName,
|
...projectsByName,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function handleFetchProjectMilestonesSuccess(state: any, action: any) {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
milestones: action.milestones,
|
|
||||||
};
|
|
||||||
}
|
}
|
@ -1,11 +1,10 @@
|
|||||||
import { GiteaUnauthorizedError } from "../../util/gitea";
|
import { GiteaUnauthorizedError } from "../../util/gitea";
|
||||||
import { put } from 'redux-saga/effects';
|
import { put } from 'redux-saga/effects';
|
||||||
import { logout } from '../actions/logout';
|
import { logout } from '../actions/logout';
|
||||||
import { saveReferer } from "../../util/referer";
|
|
||||||
|
|
||||||
export function* failuresSaga(action) {
|
export function* failuresSaga(action) {
|
||||||
if (action.error instanceof GiteaUnauthorizedError) {
|
const err = action.error;
|
||||||
saveReferer();
|
if (err instanceof GiteaUnauthorizedError) {
|
||||||
yield put(logout());
|
yield put(logout());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
import { put, call, retry } from 'redux-saga/effects';
|
import { put, call, retry } from 'redux-saga/effects';
|
||||||
import {
|
import {
|
||||||
FETCH_ISSUES_SUCCESS, FETCH_ISSUES_FAILURE,
|
FETCH_ISSUES_SUCCESS, FETCH_ISSUES_FAILURE,
|
||||||
ADD_LABEL_FAILURE, ADD_LABEL_SUCCESS,
|
ADD_LABEL_FAILURE, ADD_LABEL_SUCCESS,
|
||||||
REMOVE_LABEL_FAILURE, REMOVE_LABEL_SUCCESS,
|
REMOVE_LABEL_FAILURE, REMOVE_LABEL_SUCCESS,
|
||||||
CREATE_ISSUE_FAILURE, CREATE_ISSUE_SUCCESS
|
CREATE_ISSUE_FAILURE, CREATE_ISSUE_SUCCESS
|
||||||
} from '../actions/issues';
|
} from '../actions/issues';
|
||||||
import { gitea } from '../../util/gitea';
|
import { gitea } from '../../util/gitea';
|
||||||
|
|
||||||
export function* fetchIssuesSaga(action: any) {
|
export function* fetchIssuesSaga(action: any) {
|
||||||
const { project, milestones } = action;
|
const { project } = action;
|
||||||
|
|
||||||
let issues = [];
|
let issues = [];
|
||||||
try {
|
try {
|
||||||
let page = 1;
|
let page = 1;
|
||||||
while (true) {
|
while(true) {
|
||||||
let pageIssues = yield call(gitea.fetchIssues.bind(gitea), project, page, milestones);
|
let pageIssues = yield call(gitea.fetchIssues.bind(gitea), action.project, page);
|
||||||
if (pageIssues.length === 0) {
|
if (pageIssues.length === 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
issues.push(...pageIssues.filter(issue => issue.pull_request === null));
|
issues.push(...pageIssues);
|
||||||
page++;
|
page++;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch(error) {
|
||||||
yield put({ type: FETCH_ISSUES_FAILURE, project, error });
|
yield put({ type: FETCH_ISSUES_FAILURE, project, error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ export function* addLabelSaga(action: any) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
yield retry(5, 250, gitea.addIssueLabel.bind(gitea), project, issueNumber, giteaLabel.id);
|
yield retry(5, 250, gitea.addIssueLabel.bind(gitea), project, issueNumber, giteaLabel.id);
|
||||||
} catch (error) {
|
} catch(error) {
|
||||||
yield put({ type: ADD_LABEL_FAILURE, error });
|
yield put({ type: ADD_LABEL_FAILURE, error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -62,11 +62,11 @@ export function* removeLabelSaga(action: any) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
yield retry(5, 250, gitea.removeIssueLabel.bind(gitea), project, issueNumber, giteaLabel.id);
|
yield retry(5, 250, gitea.removeIssueLabel.bind(gitea), project, issueNumber, giteaLabel.id);
|
||||||
} catch (error) {
|
} catch(error) {
|
||||||
yield put({ type: REMOVE_LABEL_FAILURE, error });
|
yield put({ type: REMOVE_LABEL_FAILURE, error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
yield put({ type: REMOVE_LABEL_SUCCESS, project, issueNumber, label });
|
yield put({ type: REMOVE_LABEL_SUCCESS, project, issueNumber, label });
|
||||||
}
|
}
|
||||||
@ -76,14 +76,19 @@ export function* createIssueSaga(action: any) {
|
|||||||
const labels = yield call(gitea.fetchProjectLabels.bind(gitea), project);
|
const labels = yield call(gitea.fetchProjectLabels.bind(gitea), project);
|
||||||
const giteaLabel = labels.find((l: any) => l.name === label)
|
const giteaLabel = labels.find((l: any) => l.name === label)
|
||||||
|
|
||||||
let issue;
|
if (!giteaLabel) {
|
||||||
try {
|
yield put({ type: CREATE_ISSUE_FAILURE, error: new Error(`Label "${label}" not found !`) });
|
||||||
issue = yield call(gitea.createIssue.bind(gitea), project, title, body, giteaLabel ? giteaLabel.id : null);
|
|
||||||
} catch (error) {
|
|
||||||
yield put({ type: CREATE_ISSUE_FAILURE, error });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let issue;
|
||||||
|
try {
|
||||||
|
issue = yield call(gitea.createIssue.bind(gitea), project, title, body, giteaLabel.id);
|
||||||
|
} catch(error) {
|
||||||
|
yield put({ type: CREATE_ISSUE_FAILURE, error });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
yield put({ type: CREATE_ISSUE_SUCCESS, project, title, label, body, issue });
|
yield put({ type: CREATE_ISSUE_SUCCESS, project, title, label, body, issue });
|
||||||
}
|
}
|
||||||
|
@ -7,22 +7,22 @@ import { Board, BoardLane } from '../../types/board';
|
|||||||
import { KanboardLane, Kanboard, KanboardCard } from '../../types/kanboard';
|
import { KanboardLane, Kanboard, KanboardCard } from '../../types/kanboard';
|
||||||
|
|
||||||
export function* moveCardSaga(action: any) {
|
export function* moveCardSaga(action: any) {
|
||||||
const {
|
const {
|
||||||
boardID, fromLaneID,
|
boardID, fromLaneID,
|
||||||
fromPosition, toLaneID,
|
fromPosition, toLaneID,
|
||||||
toPosition,
|
toPosition,
|
||||||
} = action;
|
} = action;
|
||||||
|
|
||||||
if (fromLaneID === toLaneID) return;
|
if (fromLaneID === toLaneID) return;
|
||||||
|
|
||||||
const { board, kanboard } = yield select(state => {
|
const { board, kanboard} = yield select(state => {
|
||||||
return {
|
return {
|
||||||
kanboard: state.kanboards.byID[boardID],
|
kanboard: state.kanboards.byID[boardID],
|
||||||
board: state.boards.byID[boardID]
|
board: state.boards.byID[boardID]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const toLane = kanboard.columns[toLaneID];
|
const toLane = kanboard.lanes[toLaneID];
|
||||||
const card = toLane.cards[toPosition];
|
const card = toLane.cards[toPosition];
|
||||||
|
|
||||||
if (!card) return;
|
if (!card) return;
|
||||||
@ -33,21 +33,21 @@ export function* moveCardSaga(action: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function* buildKanboardSaga(action: any) {
|
export function* buildKanboardSaga(action: any) {
|
||||||
const { board, milestones } = action;
|
const { board } = action;
|
||||||
console.log("milestones", milestones);
|
|
||||||
let kanboard;
|
let kanboard;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
for (let p, i = 0; (p = board.projects[i]); i++) {
|
for (let p, i = 0; (p = board.projects[i]); i++) {
|
||||||
const { project } = yield fetchIssues(p, "test");
|
const { project } = yield fetchIssues(p);
|
||||||
yield fetchIssuesSaga({ project: project, milestones: milestones });
|
yield fetchIssuesSaga({ project });
|
||||||
}
|
}
|
||||||
|
|
||||||
const issues = yield select(state => state.issues);
|
const issues = yield select(state => state.issues);
|
||||||
|
|
||||||
kanboard = createKanboard(board, issues);
|
kanboard = createKanboard(board, issues);
|
||||||
|
|
||||||
} catch (error) {
|
} catch(error) {
|
||||||
yield put({ type: BUILD_KANBOARD_FAILURE, error });
|
yield put({ type: BUILD_KANBOARD_FAILURE, error });
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -56,14 +56,14 @@ export function* buildKanboardSaga(action: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function* refreshKanboardSaga(action: any) {
|
export function* refreshKanboardSaga(action: any) {
|
||||||
const { project, milestones } = action;
|
const { project } = action;
|
||||||
const boards = yield select(state => state.boards);
|
const boards = yield select(state => state.boards);
|
||||||
const boardValues = Object.values(boards.byID);
|
const boardValues = Object.values(boards.byID);
|
||||||
|
|
||||||
for (let b: any, i = 0; (b = boardValues[i]); i++) {
|
for (let b: any, i = 0; (b = boardValues[i]); i++) {
|
||||||
const hasProject = b.projects.indexOf(project) !== -1;
|
const hasProject = b.projects.indexOf(project) !== -1;
|
||||||
if (!hasProject) continue;
|
if (!hasProject) continue;
|
||||||
yield put(buildKanboard(b, milestones));
|
yield put(buildKanboard(b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,19 +73,19 @@ function createCards(projects: Project[], issues: any, lane: BoardLane, rest: Se
|
|||||||
const projectIssues = p in issues.byProject ? issues.byProject[p] : [];
|
const projectIssues = p in issues.byProject ? issues.byProject[p] : [];
|
||||||
|
|
||||||
return projectIssues.reduce((projectCards: KanboardCard[], issue: any) => {
|
return projectIssues.reduce((projectCards: KanboardCard[], issue: any) => {
|
||||||
|
|
||||||
const hasLabel = issue.labels.some((l: any) => l.name === lane.issueLabel);
|
const hasLabel = issue.labels.some((l: any) => l.name === lane.issueLabel);
|
||||||
const { card, memoized } = getMemoizedKanboardCard(issue.id, issue.title, p, issue);
|
const card = getMemoizedKanboardCard(issue.id, issue.title, p, issue);
|
||||||
|
|
||||||
if (hasLabel) {
|
if (hasLabel) {
|
||||||
projectCards.push(card);
|
projectCards.push(card);
|
||||||
rest.delete(card);
|
rest.delete(card);
|
||||||
} else {
|
} else {
|
||||||
if (!memoized) rest.add(card);
|
rest.add(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectCards;
|
return projectCards;
|
||||||
|
|
||||||
}, laneCards);
|
}, laneCards);
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
@ -93,21 +93,13 @@ function createCards(projects: Project[], issues: any, lane: BoardLane, rest: Se
|
|||||||
return cards;
|
return cards;
|
||||||
}
|
}
|
||||||
|
|
||||||
const kanboardCardMemo: { [key: string]: KanboardCard } = {};
|
const kanboardCardMemo: {[key: string]: KanboardCard} = {};
|
||||||
|
|
||||||
function getKanboardCardMemoizationKey(id: number, project: Project, issue: Issue) {
|
function getMemoizedKanboardCard(id: number, title: string, project: Project, issue: Issue): KanboardCard {
|
||||||
return `${project.id}-${issue.id}-${id}`;
|
const key = `${project.id}-${issue.id}-${id}`;
|
||||||
}
|
if (kanboardCardMemo.hasOwnProperty(key)) return kanboardCardMemo[key];
|
||||||
|
|
||||||
function isKanboardCardMemoized(key: string) {
|
|
||||||
return kanboardCardMemo.hasOwnProperty(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMemoizedKanboardCard(id: number, title: string, project: Project, issue: Issue) {
|
|
||||||
const key = getKanboardCardMemoizationKey(id, project, issue);
|
|
||||||
if (isKanboardCardMemoized(key)) return { card: kanboardCardMemo[key], memoized: true };
|
|
||||||
kanboardCardMemo[key] = { id, title, project, issue };
|
kanboardCardMemo[key] = { id, title, project, issue };
|
||||||
return { card: kanboardCardMemo[key], memoized: false };
|
return kanboardCardMemo[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetKandboarCardMemo() {
|
function resetKandboarCardMemo() {
|
||||||
@ -115,9 +107,9 @@ function resetKandboarCardMemo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createKanboardLanes(board: Board, issues: any): KanboardLane[] {
|
function createKanboardLanes(board: Board, issues: any): KanboardLane[] {
|
||||||
const lanes: KanboardLane[] = [];
|
const lanes: KanboardLane[] = [];
|
||||||
const rest = new Set<KanboardCard>();
|
const rest = new Set<KanboardCard>();
|
||||||
|
|
||||||
resetKandboarCardMemo();
|
resetKandboarCardMemo();
|
||||||
|
|
||||||
board.lanes.forEach((l: BoardLane, i: number) => {
|
board.lanes.forEach((l: BoardLane, i: number) => {
|
||||||
@ -136,7 +128,7 @@ function createKanboardLanes(board: Board, issues: any): KanboardLane[] {
|
|||||||
});
|
});
|
||||||
|
|
||||||
resetKandboarCardMemo();
|
resetKandboarCardMemo();
|
||||||
|
|
||||||
return lanes;
|
return lanes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,8 +137,8 @@ function createKanboard(board: Board, issues: any) {
|
|||||||
|
|
||||||
const kanboard = {
|
const kanboard = {
|
||||||
id: board.id,
|
id: board.id,
|
||||||
columns: createKanboardLanes(board, issues),
|
lanes: createKanboardLanes(board, issues),
|
||||||
};
|
};
|
||||||
|
|
||||||
return kanboard;
|
return kanboard;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { put, call } from 'redux-saga/effects';
|
import { put, call } from 'redux-saga/effects';
|
||||||
import { FETCH_PROJECTS_SUCCESS, FETCH_PROJECTS_FAILURE, FETCH_PROJECT_MILESTONES_FAILURE, FETCH_PROJECT_MILESTONES_SUCCESS } from '../actions/projects';
|
import { FETCH_PROJECTS_SUCCESS, FETCH_PROJECTS_FAILURE } from '../actions/projects';
|
||||||
import { gitea } from '../../util/gitea';
|
import { gitea } from '../../util/gitea';
|
||||||
|
|
||||||
export function* fetchProjectsSaga() {
|
export function* fetchProjectsSaga() {
|
||||||
@ -7,23 +7,10 @@ export function* fetchProjectsSaga() {
|
|||||||
let projects;
|
let projects;
|
||||||
try {
|
try {
|
||||||
projects = yield call(gitea.fetchUserProjects.bind(gitea))
|
projects = yield call(gitea.fetchUserProjects.bind(gitea))
|
||||||
} catch (error) {
|
} catch(error) {
|
||||||
yield put({ type: FETCH_PROJECTS_FAILURE, error });
|
yield put({ type: FETCH_PROJECTS_FAILURE, error });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put({ type: FETCH_PROJECTS_SUCCESS, projects });
|
yield put({ type: FETCH_PROJECTS_SUCCESS, projects });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* fetchProjectMilestonesSaga(action: any) {
|
|
||||||
const { project } = action;
|
|
||||||
let milestones;
|
|
||||||
try {
|
|
||||||
milestones = yield call(gitea.fetchMilestones.bind(gitea), project)
|
|
||||||
} catch (error) {
|
|
||||||
yield put({ type: FETCH_PROJECT_MILESTONES_FAILURE, error });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield put({ type: FETCH_PROJECT_MILESTONES_SUCCESS, milestones });
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
import { hasReferer, getReferer, clearReferer } from '../../util/referer';
|
|
||||||
|
|
||||||
export function* navigateToRefererSaga() {
|
|
||||||
if (!hasReferer()) return;
|
|
||||||
const referer = getReferer();
|
|
||||||
console.log("Redirecting to referer", referer);
|
|
||||||
clearReferer();
|
|
||||||
window.location.hash = referer;
|
|
||||||
}
|
|
@ -4,17 +4,15 @@ import { FETCH_BOARDS_REQUEST, SAVE_BOARD_REQUEST, DELETE_BOARD_REQUEST } from '
|
|||||||
import { fetchBoardsSaga, saveBoardSaga, deleteBoardSaga } 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, FETCH_PROJECT_MILESTONES_REQUEST } from '../actions/projects';
|
import { FETCH_PROJECTS_REQUEST } from '../actions/projects';
|
||||||
import { fetchProjectMilestonesSaga, fetchProjectsSaga } from './projects';
|
import { fetchProjectsSaga } from './projects';
|
||||||
import { LOGOUT_REQUEST, LOGOUT_SUCCESS } from '../actions/logout';
|
import { LOGOUT_REQUEST, LOGOUT_SUCCESS } from '../actions/logout';
|
||||||
import { logoutSaga, logoutSuccessSaga } 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';
|
||||||
import { navigateToRefererSaga } from './referer';
|
|
||||||
|
|
||||||
export function* rootSaga() {
|
export function* rootSaga() {
|
||||||
yield all([
|
yield all([
|
||||||
navigateToRefererSaga(),
|
|
||||||
takeEvery(patternFromRegExp(/^.*_FAILURE/), failuresSaga),
|
takeEvery(patternFromRegExp(/^.*_FAILURE/), failuresSaga),
|
||||||
takeLatest(FETCH_BOARDS_REQUEST, fetchBoardsSaga),
|
takeLatest(FETCH_BOARDS_REQUEST, fetchBoardsSaga),
|
||||||
takeLatest(BUILD_KANBOARD_REQUEST, buildKanboardSaga),
|
takeLatest(BUILD_KANBOARD_REQUEST, buildKanboardSaga),
|
||||||
@ -22,7 +20,6 @@ export function* rootSaga() {
|
|||||||
takeLatest(DELETE_BOARD_REQUEST, deleteBoardSaga),
|
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),
|
||||||
takeLatest(FETCH_PROJECT_MILESTONES_REQUEST, fetchProjectMilestonesSaga),
|
|
||||||
takeEvery(MOVE_CARD, moveCardSaga),
|
takeEvery(MOVE_CARD, moveCardSaga),
|
||||||
takeEvery(ADD_LABEL_REQUEST, addLabelSaga),
|
takeEvery(ADD_LABEL_REQUEST, addLabelSaga),
|
||||||
takeEvery(REMOVE_LABEL_REQUEST, removeLabelSaga),
|
takeEvery(REMOVE_LABEL_REQUEST, removeLabelSaga),
|
||||||
@ -33,7 +30,7 @@ export function* rootSaga() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function patternFromRegExp(re: any) {
|
export function patternFromRegExp(re: any) {
|
||||||
return (action: any) => {
|
return (action: any) => {
|
||||||
return re.test(action.type);
|
return re.test(action.type);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createStore, applyMiddleware, compose } from 'redux'
|
import { createStore, applyMiddleware } from 'redux'
|
||||||
import createSagaMiddleware from 'redux-saga'
|
import createSagaMiddleware from 'redux-saga'
|
||||||
import { rootReducer } from './reducers/root'
|
import { rootReducer } from './reducers/root'
|
||||||
import { rootSaga } from './sagas/root'
|
import { rootSaga } from './sagas/root'
|
||||||
@ -14,8 +14,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
reduxMiddlewares.push(loggerMiddleware);
|
reduxMiddlewares.push(loggerMiddleware);
|
||||||
}
|
}
|
||||||
|
|
||||||
const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
|
||||||
|
|
||||||
// create the saga middleware
|
// create the saga middleware
|
||||||
const sagaMiddleware = createSagaMiddleware()
|
const sagaMiddleware = createSagaMiddleware()
|
||||||
reduxMiddlewares.push(sagaMiddleware);
|
reduxMiddlewares.push(sagaMiddleware);
|
||||||
@ -23,7 +21,7 @@ reduxMiddlewares.push(sagaMiddleware);
|
|||||||
// mount it on the Store
|
// mount it on the Store
|
||||||
export const store = createStore(
|
export const store = createStore(
|
||||||
rootReducer,
|
rootReducer,
|
||||||
composeEnhancers(applyMiddleware(...reduxMiddlewares)),
|
applyMiddleware(...reduxMiddlewares)
|
||||||
)
|
)
|
||||||
|
|
||||||
// then run the saga
|
// then run the saga
|
||||||
|
@ -2,26 +2,17 @@
|
|||||||
export class GiteaUnauthorizedError extends Error {
|
export class GiteaUnauthorizedError extends Error {
|
||||||
constructor(...args: any[]) {
|
constructor(...args: any[]) {
|
||||||
super(...args)
|
super(...args)
|
||||||
Object.setPrototypeOf(this, GiteaUnauthorizedError.prototype);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GiteaClient {
|
export class GiteaClient {
|
||||||
|
|
||||||
fetchIssues(project: any, page = 1, milestones = "") {
|
fetchIssues(project: any, page = 1) {
|
||||||
return fetch(`/gitea/api/v1/repos/${project}/issues?page=${page}&milestones=${milestones}`)
|
return fetch(`/gitea/api/v1/repos/${project}/issues?page=${page}`)
|
||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
.then(this.assertOk)
|
.then(this.assertOk)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
;
|
;
|
||||||
}
|
|
||||||
|
|
||||||
fetchMilestones(project: any) {
|
|
||||||
return fetch(`/gitea/api/v1/repos/${project}/milestones`)
|
|
||||||
.then(this.assertAuthorization)
|
|
||||||
.then(this.assertOk)
|
|
||||||
.then(res => res.json())
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchUserProjects() {
|
fetchUserProjects() {
|
||||||
@ -29,7 +20,7 @@ export class GiteaClient {
|
|||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
.then(this.assertOk)
|
.then(this.assertOk)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
addIssueLabel(project: any, issueNumber: any, labelID: any) {
|
addIssueLabel(project: any, issueNumber: any, labelID: any) {
|
||||||
@ -40,9 +31,9 @@ export class GiteaClient {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({ labels: [labelID] }),
|
body: JSON.stringify({ labels: [labelID] }),
|
||||||
})
|
})
|
||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
.then(this.assertOk)
|
.then(this.assertOk)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchProjectLabels(project: any) {
|
fetchProjectLabels(project: any) {
|
||||||
@ -50,15 +41,15 @@ export class GiteaClient {
|
|||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
.then(this.assertOk)
|
.then(this.assertOk)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeIssueLabel(project: any, issueNumber: any, labelID: any) {
|
removeIssueLabel(project: any, issueNumber: any, labelID: any) {
|
||||||
return fetch(`/gitea/api/v1/repos/${project}/issues/${issueNumber}/labels/${labelID}`, {
|
return fetch(`/gitea/api/v1/repos/${project}/issues/${issueNumber}/labels/${labelID}`, {
|
||||||
method: 'DELETE'
|
method: 'DELETE'
|
||||||
})
|
})
|
||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
.then(this.assertOk)
|
.then(this.assertOk)
|
||||||
}
|
}
|
||||||
|
|
||||||
createIssue(project: any, title: any, body: any, labelID: any) {
|
createIssue(project: any, title: any, body: any, labelID: any) {
|
||||||
@ -70,12 +61,12 @@ export class GiteaClient {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
title,
|
title,
|
||||||
body,
|
body,
|
||||||
labels: labelID ? [labelID] : undefined,
|
labels: [labelID],
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(this.assertAuthorization)
|
.then(this.assertAuthorization)
|
||||||
.then(this.assertOk)
|
.then(this.assertOk)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
assertOk(res: any) {
|
assertOk(res: any) {
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
const localStorage = window.localStorage;
|
|
||||||
const refererKey = 'referer';
|
|
||||||
|
|
||||||
export function getReferer() {
|
|
||||||
return localStorage.getItem(refererKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveReferer() {
|
|
||||||
console.log("Saving referer", window.location.hash);
|
|
||||||
localStorage.setItem(refererKey, window.location.hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hasReferer() {
|
|
||||||
return !!getReferer();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearReferer() {
|
|
||||||
localStorage.removeItem(refererKey);
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [{
|
rules: [{
|
||||||
test: /\.s(a|c)ss$/,
|
test: /\.scss$/,
|
||||||
use: [
|
use: [
|
||||||
MiniCssExtractPlugin.loader,
|
MiniCssExtractPlugin.loader,
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ func getServiceContainer(conf *config.Config) (*service.Container, error) {
|
|||||||
|
|
||||||
ctn.Provide(
|
ctn.Provide(
|
||||||
session.ServiceName,
|
session.ServiceName,
|
||||||
gorilla.ServiceProvider("gengitkan", cookieStore),
|
gorilla.ServiceProvider("gitea-kan", cookieStore),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create and expose config service provider
|
// Create and expose config service provider
|
||||||
|
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
9
|
14
debian/control
vendored
Normal file
14
debian/control
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Source: gitea-kan
|
||||||
|
Section: unknown
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: William Petit <wpetit@cadoles.com>
|
||||||
|
Build-Depends: debhelper (>= 8.0.0), wget, ca-certificates, tar
|
||||||
|
Standards-Version: 3.9.4
|
||||||
|
Homepage: http://forge.cadoles.com/wpetit/gitea-kan
|
||||||
|
Vcs-Git: http://forge.cadoles.com/wpetit/gitea-kan.git
|
||||||
|
Vcs-Browser: http://forge.cadoles.com/wpetit/gitea-kan
|
||||||
|
|
||||||
|
Package: gitea-kan
|
||||||
|
Architecture: amd64
|
||||||
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
|
Description: Application type "Kanboard" connectée à Gitea
|
1
debian/gitea-kan.dirs
vendored
Normal file
1
debian/gitea-kan.dirs
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
var/lib/gitea-kan
|
13
debian/gitea-kan.service
vendored
Normal file
13
debian/gitea-kan.service
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Application type "Kanboard" connectée à Gitea
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Environment=GITEAKAN_HTTP_PUBDIR=/usr/share/gitea-kan/public
|
||||||
|
Environment=GITEAKAN_DATA_DBPATH=/var/lib/gitea-kan/data.db
|
||||||
|
ExecStart=/usr/bin/gitea-kan -workdir /usr/share/gitea-kan -config /etc/gitea-kan/server.conf
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
54
debian/rules
vendored
Normal file
54
debian/rules
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
export DH_VERBOSE=1
|
||||||
|
|
||||||
|
GO_VERSION := 1.13.5
|
||||||
|
OS := linux
|
||||||
|
ARCH := amd64
|
||||||
|
GOPATH=$(HOME)/go
|
||||||
|
|
||||||
|
ifeq (, $(shell which go 2>/dev/null))
|
||||||
|
override_dh_auto_build: install-go
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq (, $(shell which node 2>/dev/null))
|
||||||
|
override_dh_auto_build: install-nodejs
|
||||||
|
endif
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with systemd
|
||||||
|
|
||||||
|
override_dh_auto_build: $(GOPATH)
|
||||||
|
cd client && npm install
|
||||||
|
GOPATH=$(GOPATH) PATH="$(PATH):/usr/local/go/bin:$(GOPATH)/bin" go mod vendor
|
||||||
|
GOPATH=$(GOPATH) PATH="$(PATH):/usr/local/go/bin:$(GOPATH)/bin" ARCH_TARGETS=$(ARCH) make release
|
||||||
|
|
||||||
|
$(GOPATH):
|
||||||
|
mkdir -p $(GOPATH)
|
||||||
|
|
||||||
|
install-go:
|
||||||
|
wget https://dl.google.com/go/go$(GO_VERSION).$(OS)-$(ARCH).tar.gz
|
||||||
|
tar -C /usr/local -xzf go$(GO_VERSION).$(OS)-$(ARCH).tar.gz
|
||||||
|
|
||||||
|
install-nodejs:
|
||||||
|
wget -O- https://deb.nodesource.com/setup_12.x | bash -
|
||||||
|
apt-get install -y nodejs
|
||||||
|
|
||||||
|
override_dh_auto_install:
|
||||||
|
|
||||||
|
mkdir -p debian/gitea-kan/usr/share/gitea-kan
|
||||||
|
mkdir -p debian/gitea-kan/etc/gitea-kan
|
||||||
|
mkdir -p debian/gitea-kan/usr/bin
|
||||||
|
|
||||||
|
cp -r release/server-$(OS)-$(ARCH)/* debian/gitea-kan/usr/share/gitea-kan/
|
||||||
|
|
||||||
|
mv debian/gitea-kan/usr/share/gitea-kan/bin/server debian/gitea-kan/usr/bin/gitea-kan
|
||||||
|
mv debian/gitea-kan/usr/share/gitea-kan/server.conf debian/gitea-kan/etc/gitea-kan/server.conf
|
||||||
|
|
||||||
|
install -d debian/gitea-kan
|
||||||
|
|
||||||
|
override_dh_strip:
|
||||||
|
|
||||||
|
override_dh_auto_test:
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.0 (native)
|
Reference in New Issue
Block a user