Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90c8b4d548 | ||
|
|
4941b51fa4 | ||
|
|
a858419f3c | ||
|
|
e28c06b85a | ||
|
|
fa2d73a2c5 | ||
|
|
80706bbdd5 | ||
|
|
db4e5a89f9 | ||
|
|
0266e4bfe2 |
+23
-5
@@ -1,11 +1,29 @@
|
|||||||
*/node_modules
|
|
||||||
*/.gitignore
|
|
||||||
*/README.md
|
*/README.md
|
||||||
|
*/.gitignore
|
||||||
|
*/node_modules
|
||||||
|
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
**/.gitkeep
|
|
||||||
|
server/**/.gitkeep
|
||||||
|
|
||||||
|
server/.env
|
||||||
|
server/.editorconfig
|
||||||
|
server/.eslintignore
|
||||||
|
server/.npmrc
|
||||||
|
server/test
|
||||||
|
server/logs
|
||||||
|
server/.tmp
|
||||||
|
|
||||||
|
server/views/*
|
||||||
|
|
||||||
server/public/*
|
server/public/*
|
||||||
server/views/*
|
!server/public/user-avatars
|
||||||
server/logs
|
server/public/user-avatars/*
|
||||||
|
!server/public/project-background-images
|
||||||
|
server/public/project-background-images/*
|
||||||
|
|
||||||
|
server/private/*
|
||||||
|
!server/private/attachments
|
||||||
|
server/private/attachments/*
|
||||||
|
|
||||||
client/build
|
client/build
|
||||||
|
|||||||
+21
-13
@@ -1,32 +1,40 @@
|
|||||||
FROM node:lts AS client-builder
|
FROM ghcr.io/plankanban/planka:base-latest as server-dependencies
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY client/package.json client/package-lock.json ./
|
COPY server/package.json server/package-lock.json .
|
||||||
|
|
||||||
RUN npm install npm@latest --global \
|
RUN npm install npm@latest --global \
|
||||||
&& npm install
|
&& npm clean-install --omit=dev
|
||||||
|
|
||||||
|
FROM node:lts AS client
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY client/package.json client/package-lock.json .
|
||||||
|
|
||||||
|
RUN npm install npm@latest --global \
|
||||||
|
&& npm clean-install --omit=dev
|
||||||
|
|
||||||
COPY client .
|
COPY client .
|
||||||
RUN DISABLE_ESLINT_PLUGIN=true npm run build
|
RUN DISABLE_ESLINT_PLUGIN=true npm run build
|
||||||
|
|
||||||
FROM ghcr.io/plankanban/planka:base-latest
|
FROM ghcr.io/plankanban/planka:base-latest
|
||||||
|
|
||||||
|
RUN apk del vips-dependencies --purge
|
||||||
|
|
||||||
|
USER node
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY server/.npmrc server/package.json server/package-lock.json ./
|
COPY --chown=node:node docker-start.sh start.sh
|
||||||
|
COPY --chown=node:node server .
|
||||||
|
|
||||||
RUN npm install npm@latest --global \
|
RUN mv .env.sample .env
|
||||||
&& npm install --production \
|
|
||||||
&& apk del vips-dependencies --purge
|
|
||||||
|
|
||||||
COPY docker-start.sh start.sh
|
COPY --from=server-dependencies --chown=node:node /app/node_modules node_modules
|
||||||
COPY server .
|
|
||||||
|
|
||||||
RUN cp .env.sample .env
|
COPY --from=client --chown=node:node /app/build public
|
||||||
|
COPY --from=client --chown=node:node /app/build/index.html views/index.ejs
|
||||||
COPY --from=client-builder /app/build public
|
|
||||||
COPY --from=client-builder /app/build/index.html views/index.ejs
|
|
||||||
|
|
||||||
VOLUME /app/public/user-avatars
|
VOLUME /app/public/user-avatars
|
||||||
VOLUME /app/public/project-background-images
|
VOLUME /app/public/project-background-images
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ There are 2 types of installation:
|
|||||||
|
|
||||||
### 1. Docker Compose
|
### 1. Docker Compose
|
||||||
|
|
||||||
[](https://hub.docker.com/r/meltyshev/planka)
|
[](https://github.com/plankanban/planka/pkgs/container/planka)
|
||||||
|
|
||||||
- Make sure you have [Docker](https://docs.docker.com/install/) and [Docker Compose](https://docs.docker.com/compose/install/) installed and operational.
|
- Make sure you have [Docker](https://docs.docker.com/install/) and [Docker Compose](https://docs.docker.com/compose/install/) installed and operational.
|
||||||
- Create `docker-compose.yml` based on [the example](https://raw.githubusercontent.com/plankanban/planka/master/docker-compose.yml). This is the ONLY file you will need. You can create this file on your own machine by copy and pasting the content.
|
- Create `docker-compose.yml` based on [the example](https://raw.githubusercontent.com/plankanban/planka/master/docker-compose.yml). This is the ONLY file you will need. You can create this file on your own machine by copy and pasting the content.
|
||||||
@@ -259,6 +259,10 @@ Restart the fail2ban service. You can check the status of your Planka jail by ru
|
|||||||
fail2ban-client status planka
|
fail2ban-client status planka
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Import from Trello
|
||||||
|
|
||||||
|
It is not yet implemented inside Planka, but for now you can use the great tool [trello2planka](https://github.com/christophenne/trello2planka) to do the import.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
Clone the repository and install dependencies:
|
Clone the repository and install dependencies:
|
||||||
|
|||||||
Generated
+2
-23
@@ -22,6 +22,7 @@
|
|||||||
"photoswipe": "^5.3.3",
|
"photoswipe": "^5.3.3",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-app-rewired": "^2.2.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
"react-datepicker": "^4.8.0",
|
"react-datepicker": "^4.8.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -31,13 +32,11 @@
|
|||||||
"react-markdown": "^8.0.3",
|
"react-markdown": "^8.0.3",
|
||||||
"react-photoswipe-gallery": "^2.2.2",
|
"react-photoswipe-gallery": "^2.2.2",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
"react-router": "^6.4.3",
|
|
||||||
"react-router-dom": "^6.4.3",
|
"react-router-dom": "^6.4.3",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-simplemde-editor": "^5.2.0",
|
"react-simplemde-editor": "^5.2.0",
|
||||||
"react-textarea-autosize": "^8.4.0",
|
"react-textarea-autosize": "^8.4.0",
|
||||||
"redux": "^4.2.0",
|
"redux": "^4.2.0",
|
||||||
"redux-first-history": "^5.1.1",
|
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-orm": "^0.16.2",
|
"redux-orm": "^0.16.2",
|
||||||
"redux-saga": "^1.2.1",
|
"redux-saga": "^1.2.1",
|
||||||
@@ -63,7 +62,6 @@
|
|||||||
"eslint-plugin-jsx-a11y": "^6.6.1",
|
"eslint-plugin-jsx-a11y": "^6.6.1",
|
||||||
"eslint-plugin-react": "^7.31.11",
|
"eslint-plugin-react": "^7.31.11",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"react-app-rewired": "^2.2.1",
|
|
||||||
"react-test-renderer": "^18.2.0"
|
"react-test-renderer": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -18972,7 +18970,6 @@
|
|||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz",
|
||||||
"integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==",
|
"integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": "^5.6.0"
|
"semver": "^5.6.0"
|
||||||
},
|
},
|
||||||
@@ -18987,7 +18984,6 @@
|
|||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver"
|
"semver": "bin/semver"
|
||||||
}
|
}
|
||||||
@@ -19951,15 +19947,6 @@
|
|||||||
"@babel/runtime": "^7.9.2"
|
"@babel/runtime": "^7.9.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/redux-first-history": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/redux-first-history/-/redux-first-history-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-ujVHv+y9wC2rqavS5tLiSu6zkw+VYrEea+/ggwVTRuutadEtwxSRlaK19ry/PTLSQtFuUF1Xu+plL5erD4roVw==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"history": "^4.7.2 || ^5.0",
|
|
||||||
"redux": "^3.6.0 || ^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/redux-logger": {
|
"node_modules/redux-logger": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
|
||||||
@@ -37164,7 +37151,6 @@
|
|||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-app-rewired/-/react-app-rewired-2.2.1.tgz",
|
||||||
"integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==",
|
"integrity": "sha512-uFQWTErXeLDrMzOJHKp0h8P1z0LV9HzPGsJ6adOtGlA/B9WfT6Shh4j2tLTTGlXOfiVx6w6iWpp7SOC5pvk+gA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"semver": "^5.6.0"
|
"semver": "^5.6.0"
|
||||||
},
|
},
|
||||||
@@ -37172,8 +37158,7 @@
|
|||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||||
"dev": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -37854,12 +37839,6 @@
|
|||||||
"@babel/runtime": "^7.9.2"
|
"@babel/runtime": "^7.9.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redux-first-history": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/redux-first-history/-/redux-first-history-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-ujVHv+y9wC2rqavS5tLiSu6zkw+VYrEea+/ggwVTRuutadEtwxSRlaK19ry/PTLSQtFuUF1Xu+plL5erD4roVw==",
|
|
||||||
"requires": {}
|
|
||||||
},
|
|
||||||
"redux-logger": {
|
"redux-logger": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
|
||||||
|
|||||||
+1
-3
@@ -69,6 +69,7 @@
|
|||||||
"photoswipe": "^5.3.3",
|
"photoswipe": "^5.3.3",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-app-rewired": "^2.2.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
"react-datepicker": "^4.8.0",
|
"react-datepicker": "^4.8.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -78,13 +79,11 @@
|
|||||||
"react-markdown": "^8.0.3",
|
"react-markdown": "^8.0.3",
|
||||||
"react-photoswipe-gallery": "^2.2.2",
|
"react-photoswipe-gallery": "^2.2.2",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
"react-router": "^6.4.3",
|
|
||||||
"react-router-dom": "^6.4.3",
|
"react-router-dom": "^6.4.3",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"react-simplemde-editor": "^5.2.0",
|
"react-simplemde-editor": "^5.2.0",
|
||||||
"react-textarea-autosize": "^8.4.0",
|
"react-textarea-autosize": "^8.4.0",
|
||||||
"redux": "^4.2.0",
|
"redux": "^4.2.0",
|
||||||
"redux-first-history": "^5.1.1",
|
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-orm": "^0.16.2",
|
"redux-orm": "^0.16.2",
|
||||||
"redux-saga": "^1.2.1",
|
"redux-saga": "^1.2.1",
|
||||||
@@ -110,7 +109,6 @@
|
|||||||
"eslint-plugin-jsx-a11y": "^6.6.1",
|
"eslint-plugin-jsx-a11y": "^6.6.1",
|
||||||
"eslint-plugin-react": "^7.31.11",
|
"eslint-plugin-react": "^7.31.11",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"react-app-rewired": "^2.2.1",
|
|
||||||
"react-test-renderer": "^18.2.0"
|
"react-test-renderer": "^18.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { Route, Routes } from 'react-router-dom';
|
import { Route, Routes } from 'react-router-dom';
|
||||||
import { HistoryRouter as Router } from 'redux-first-history/rr6';
|
import { ReduxRouter } from '../lib/redux-router';
|
||||||
|
|
||||||
import Paths from '../constants/Paths';
|
import Paths from '../constants/Paths';
|
||||||
import LoginContainer from '../containers/LoginContainer';
|
import LoginContainer from '../containers/LoginContainer';
|
||||||
@@ -19,7 +19,7 @@ import '../styles.module.scss';
|
|||||||
function Root({ store, history }) {
|
function Root({ store, history }) {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Router history={history}>
|
<ReduxRouter history={history}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={Paths.LOGIN} element={<LoginContainer />} />
|
<Route path={Paths.LOGIN} element={<LoginContainer />} />
|
||||||
<Route path={Paths.ROOT} element={<CoreWrapperContainer />} />
|
<Route path={Paths.ROOT} element={<CoreWrapperContainer />} />
|
||||||
@@ -28,7 +28,7 @@ function Root({ store, history }) {
|
|||||||
<Route path={Paths.CARDS} element={<CoreWrapperContainer />} />
|
<Route path={Paths.CARDS} element={<CoreWrapperContainer />} />
|
||||||
<Route path="*" element={<NotFound />} />
|
<Route path="*" element={<NotFound />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</ReduxRouter>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { push } from 'redux-first-history';
|
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
|
import { push } from '../lib/redux-router';
|
||||||
|
|
||||||
import selectors from '../selectors';
|
import selectors from '../selectors';
|
||||||
import entryActions from '../entry-actions';
|
import entryActions from '../entry-actions';
|
||||||
|
|||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
import { createBrowserHistory } from 'history';
|
||||||
|
|
||||||
|
export default createBrowserHistory();
|
||||||
+2
-1
@@ -1,7 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
|
|
||||||
import store, { history } from './store';
|
import store from './store';
|
||||||
|
import history from './history';
|
||||||
import Root from './components/Root';
|
import Root from './components/Root';
|
||||||
|
|
||||||
import './i18n';
|
import './i18n';
|
||||||
|
|||||||
@@ -80,8 +80,10 @@ export default (WrappedComponent, defaultProps) => {
|
|||||||
popperModifiers={[
|
popperModifiers={[
|
||||||
{
|
{
|
||||||
name: 'preventOverflow',
|
name: 'preventOverflow',
|
||||||
|
enabled: true,
|
||||||
options: {
|
options: {
|
||||||
boundariesElement: 'window',
|
altAxis: true,
|
||||||
|
padding: 20,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import React, { useLayoutEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { Router } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { handleLocationChange } from './actions';
|
||||||
|
|
||||||
|
function ReduxRouter({ children, history, selector, basename }) {
|
||||||
|
const state = useSelector(selector);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const unlisten = history.listen((nextState) => {
|
||||||
|
dispatch(handleLocationChange(nextState.location, nextState.action));
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(handleLocationChange(history.location, history.action, true));
|
||||||
|
|
||||||
|
return unlisten;
|
||||||
|
}, [history, dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Router
|
||||||
|
basename={basename}
|
||||||
|
location={state.location}
|
||||||
|
navigationType={state.action}
|
||||||
|
navigator={history}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReduxRouter.propTypes = {
|
||||||
|
children: PropTypes.element.isRequired,
|
||||||
|
history: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
|
||||||
|
selector: PropTypes.func,
|
||||||
|
basename: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
ReduxRouter.defaultProps = {
|
||||||
|
selector: ({ router }) => router,
|
||||||
|
basename: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReduxRouter;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
export const LOCATION_CHANGE_HANDLE = '@@router/LOCATION_CHANGE_HANDLE';
|
||||||
|
|
||||||
|
export const handleLocationChange = (location, action, isFirstRendering = false) => ({
|
||||||
|
type: LOCATION_CHANGE_HANDLE,
|
||||||
|
payload: {
|
||||||
|
location,
|
||||||
|
action,
|
||||||
|
isFirstRendering,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const HISTORY_METHOD_CALL = '@@router/HISTORY_METHOD_CALL';
|
||||||
|
|
||||||
|
const createHistoryMethodCaller = (method) => {
|
||||||
|
return (...args) => ({
|
||||||
|
type: HISTORY_METHOD_CALL,
|
||||||
|
payload: {
|
||||||
|
method,
|
||||||
|
args,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const push = createHistoryMethodCaller('push');
|
||||||
|
export const replace = createHistoryMethodCaller('replace');
|
||||||
|
export const go = createHistoryMethodCaller('go');
|
||||||
|
export const back = createHistoryMethodCaller('back');
|
||||||
|
export const forward = createHistoryMethodCaller('forward');
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { HISTORY_METHOD_CALL } from './actions';
|
||||||
|
|
||||||
|
const createRouterMiddleware = (history) => {
|
||||||
|
// eslint-disable-next-line consistent-return
|
||||||
|
return () => (next) => (action) => {
|
||||||
|
if (action.type !== HISTORY_METHOD_CALL) {
|
||||||
|
return next(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
payload: { method, args },
|
||||||
|
} = action;
|
||||||
|
|
||||||
|
history[method](...args);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createRouterMiddleware;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { LOCATION_CHANGE_HANDLE } from './actions';
|
||||||
|
|
||||||
|
const createRouterReducer = (history) => {
|
||||||
|
const initialState = {
|
||||||
|
location: history.location,
|
||||||
|
action: history.action,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (state = initialState, { type, payload } = {}) => {
|
||||||
|
if (type === LOCATION_CHANGE_HANDLE) {
|
||||||
|
const { location, action, isFirstRendering } = payload;
|
||||||
|
|
||||||
|
if (isFirstRendering) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
location,
|
||||||
|
action,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default createRouterReducer;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export {
|
||||||
|
LOCATION_CHANGE_HANDLE,
|
||||||
|
HISTORY_METHOD_CALL,
|
||||||
|
push,
|
||||||
|
replace,
|
||||||
|
go,
|
||||||
|
back,
|
||||||
|
forward,
|
||||||
|
} from './actions';
|
||||||
|
export { default as createRouterReducer } from './create-router-reducer';
|
||||||
|
export { default as createRouterMiddleware } from './create-router-middleware';
|
||||||
|
export { default as ReduxRouter } from './ReduxRouter';
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LOCATION_CHANGE } from 'redux-first-history';
|
import { LOCATION_CHANGE_HANDLE } from '../lib/redux-router';
|
||||||
|
|
||||||
import ActionTypes from '../constants/ActionTypes';
|
import ActionTypes from '../constants/ActionTypes';
|
||||||
import ModalTypes from '../constants/ModalTypes';
|
import ModalTypes from '../constants/ModalTypes';
|
||||||
@@ -12,7 +12,7 @@ const initialState = {
|
|||||||
// eslint-disable-next-line default-param-last
|
// eslint-disable-next-line default-param-last
|
||||||
export default (state = initialState, { type, payload }) => {
|
export default (state = initialState, { type, payload }) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LOCATION_CHANGE:
|
case LOCATION_CHANGE_HANDLE:
|
||||||
case ActionTypes.MODAL_CLOSE:
|
case ActionTypes.MODAL_CLOSE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
import { routerReducer } from '../redux-history-context';
|
import { createRouterReducer } from '../lib/redux-router';
|
||||||
|
|
||||||
export default routerReducer;
|
import history from '../history';
|
||||||
|
|
||||||
|
export default createRouterReducer(history);
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import { createBrowserHistory } from 'history';
|
|
||||||
import { createReduxHistoryContext } from 'redux-first-history';
|
|
||||||
|
|
||||||
export const { createReduxHistory, routerMiddleware, routerReducer } = createReduxHistoryContext({
|
|
||||||
history: createBrowserHistory(),
|
|
||||||
});
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { call, put, select, take } from 'redux-saga/effects';
|
import { call, put, select, take } from 'redux-saga/effects';
|
||||||
import { push } from 'redux-first-history';
|
import { push } from '../../../lib/redux-router';
|
||||||
|
|
||||||
import request from '../request';
|
import request from '../request';
|
||||||
import selectors from '../../../selectors';
|
import selectors from '../../../selectors';
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { takeEvery } from 'redux-saga/effects';
|
import { takeEvery } from 'redux-saga/effects';
|
||||||
import { LOCATION_CHANGE } from 'redux-first-history';
|
import { LOCATION_CHANGE_HANDLE } from '../../../lib/redux-router';
|
||||||
|
|
||||||
import services from '../services';
|
import services from '../services';
|
||||||
|
|
||||||
export default function* routerWatchers() {
|
export default function* routerWatchers() {
|
||||||
yield takeEvery(LOCATION_CHANGE, () => services.handleLocationChange());
|
yield takeEvery(LOCATION_CHANGE_HANDLE, () => services.handleLocationChange());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { call, put, select } from 'redux-saga/effects';
|
import { call, put, select } from 'redux-saga/effects';
|
||||||
import { push } from 'redux-first-history';
|
import { push } from '../../../lib/redux-router';
|
||||||
|
|
||||||
import selectors from '../../../selectors';
|
import selectors from '../../../selectors';
|
||||||
import Paths from '../../../constants/Paths';
|
import Paths from '../../../constants/Paths';
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { takeEvery } from 'redux-saga/effects';
|
import { takeEvery } from 'redux-saga/effects';
|
||||||
import { LOCATION_CHANGE } from 'redux-first-history';
|
import { LOCATION_CHANGE_HANDLE } from '../../../lib/redux-router';
|
||||||
|
|
||||||
import services from '../services';
|
import services from '../services';
|
||||||
|
|
||||||
export default function* routerWatchers() {
|
export default function* routerWatchers() {
|
||||||
yield takeEvery(LOCATION_CHANGE, () => services.handleLocationChange());
|
yield takeEvery(LOCATION_CHANGE_HANDLE, () => services.handleLocationChange());
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-7
@@ -1,13 +1,14 @@
|
|||||||
import { applyMiddleware, legacy_createStore as createStore, compose as reduxCompose } from 'redux';
|
import { applyMiddleware, legacy_createStore as createStore, compose as reduxCompose } from 'redux';
|
||||||
import createSagaMiddleware from 'redux-saga';
|
import createSagaMiddleware from 'redux-saga';
|
||||||
|
import { createRouterMiddleware } from './lib/redux-router';
|
||||||
|
|
||||||
import rootReducer from './reducers';
|
import rootReducer from './reducers';
|
||||||
import rootSaga from './sagas';
|
import rootSaga from './sagas';
|
||||||
import { createReduxHistory, routerMiddleware } from './redux-history-context';
|
import history from './history';
|
||||||
|
|
||||||
const sagaMiddleware = createSagaMiddleware();
|
const sagaMiddleware = createSagaMiddleware();
|
||||||
|
|
||||||
const middlewares = [sagaMiddleware, routerMiddleware];
|
const middlewares = [sagaMiddleware, createRouterMiddleware(history)];
|
||||||
|
|
||||||
let compose = reduxCompose;
|
let compose = reduxCompose;
|
||||||
|
|
||||||
@@ -22,10 +23,6 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = createStore(rootReducer, compose(applyMiddleware(...middlewares)));
|
export default createStore(rootReducer, compose(applyMiddleware(...middlewares)));
|
||||||
|
|
||||||
sagaMiddleware.run(rootSaga);
|
sagaMiddleware.run(rootSaga);
|
||||||
|
|
||||||
export default store;
|
|
||||||
|
|
||||||
export const history = createReduxHistory(store);
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "planka",
|
"name": "planka",
|
||||||
"version": "1.8.6",
|
"version": "1.8.8",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "planka",
|
"name": "planka",
|
||||||
"version": "1.8.6",
|
"version": "1.8.8",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "planka",
|
"name": "planka",
|
||||||
"version": "1.8.6",
|
"version": "1.8.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://plankanban.github.io/planka",
|
"homepage": "https://plankanban.github.io/planka",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
Reference in New Issue
Block a user