From e4b0a16cf068cc0ee3057e93abac839e5751ca8b Mon Sep 17 00:00:00 2001 From: Enrico Fasoli Date: Fri, 9 Feb 2018 17:49:39 +0100 Subject: [PATCH] implemented persistence with boards opened before --- src/actions/actionTypes.js | 1 + src/actions/board.js | 8 ++++++++ src/components/BoardEditorForm.js | 2 +- src/components/Boards.js | 4 ++-- src/components/BoardsItem.js | 15 +++++++++++---- src/components/OpenBoardForm.js | 2 +- src/containers/Boards.js | 12 +++++++++--- src/containers/WithBoard.js | 2 +- src/reducers/boards.js | 14 +++++++++++++- src/sagas/boards.js | 14 +++++++++++--- src/sagas/index.js | 20 +++++++++++++++++--- src/sagas/persistence.js | 16 ++++++++++++++++ src/utils/ipfs.js | 4 ++-- src/utils/orbitdb.js | 6 ++++++ src/utils/persistence.js | 16 ++++++++++++++++ 15 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 src/sagas/persistence.js create mode 100644 src/utils/persistence.js diff --git a/src/actions/actionTypes.js b/src/actions/actionTypes.js index 0202029..1170cd2 100644 --- a/src/actions/actionTypes.js +++ b/src/actions/actionTypes.js @@ -4,6 +4,7 @@ export const UPDATE_BOARD_METADATA = 'UPDATE_BOARD_METADATA' export const OPEN_BOARD = 'OPEN_BOARD' export const OPENED_BOARD = 'OPENED_BOARD' +export const CLOSE_BOARD = 'CLOSE_BOARD' export const UPDATE_BOARD = 'UPDATE_BOARD' diff --git a/src/actions/board.js b/src/actions/board.js index 2859142..74102df 100644 --- a/src/actions/board.js +++ b/src/actions/board.js @@ -1,5 +1,6 @@ import { OPEN_BOARD, + CLOSE_BOARD, OPENED_BOARD, UPDATE_BOARD_METADATA } from './actionTypes' @@ -24,4 +25,11 @@ export function updateBoardMetadata(address, metadata) { address, metadata } +} + +export function closeBoard(address) { + return { + type: CLOSE_BOARD, + address + } } \ No newline at end of file diff --git a/src/components/BoardEditorForm.js b/src/components/BoardEditorForm.js index e9c30a0..a5add3b 100644 --- a/src/components/BoardEditorForm.js +++ b/src/components/BoardEditorForm.js @@ -37,7 +37,7 @@ export default class BoardEditorForm extends Component { onChange={this.updateTitle.bind(this)} /> - +
@@ -65,7 +65,7 @@ export default function Boards({ stats, boards, createBoard }) { - {Object.values(boards).map(board => )} + {Object.values(boards).map(board => )} {Object.keys(boards).length === 0 ? No boards opened : null} diff --git a/src/components/BoardsItem.js b/src/components/BoardsItem.js index 90ea0b4..2022098 100644 --- a/src/components/BoardsItem.js +++ b/src/components/BoardsItem.js @@ -1,9 +1,9 @@ import React from 'react' -import { List, Button, Card } from 'semantic-ui-react' +import { Icon, List, Button, Card } from 'semantic-ui-react' import { Link } from 'react-router-dom' import { shortenAddress } from '../utils/orbitdb' -export default function BoardsItem({ address, metadata, name }) { +export default function BoardsItem({ address, metadata, name, closeBoard }) { return @@ -29,8 +29,15 @@ export default function BoardsItem({ address, metadata, name }) { - - + +
+ + +
} \ No newline at end of file diff --git a/src/components/OpenBoardForm.js b/src/components/OpenBoardForm.js index 8051aee..f15a51a 100644 --- a/src/components/OpenBoardForm.js +++ b/src/components/OpenBoardForm.js @@ -43,7 +43,7 @@ export default class OpenBoardForm extends Component { - diff --git a/src/containers/Boards.js b/src/containers/Boards.js index 29cea43..8997968 100644 --- a/src/containers/Boards.js +++ b/src/containers/Boards.js @@ -3,11 +3,16 @@ import { connect } from 'react-redux' import { push } from 'react-router-redux' import BoardsComponent from '../components/Boards' import WithStats from './WithStats' +import { closeBoard } from '../actions/board' const WrappedComponent = WithStats(BoardsComponent) -function Boards({ boards, createBoard }) { - return +function Boards({ boards, createBoard, closeBoard }) { + return } function mapStateToProps(state){ @@ -18,7 +23,8 @@ function mapStateToProps(state){ function mapDispatchToProps(dispatch){ return { - createBoard: () => dispatch(push('/b/new')) + createBoard: () => dispatch(push('/b/new')), + closeBoard: address => dispatch(closeBoard(address)), } } diff --git a/src/containers/WithBoard.js b/src/containers/WithBoard.js index 8dee0bd..bd86301 100644 --- a/src/containers/WithBoard.js +++ b/src/containers/WithBoard.js @@ -12,7 +12,7 @@ function mapStateToProps(state){ function mapDispatchToProps(dispatch){ return { - openBoard: address => dispatch(openBoard({ address })) + openBoard: address => dispatch(openBoard({ address, redirect: false })) } } diff --git a/src/reducers/boards.js b/src/reducers/boards.js index 21fa4c9..16b4474 100644 --- a/src/reducers/boards.js +++ b/src/reducers/boards.js @@ -1,5 +1,6 @@ import { OPENED_BOARD, + CLOSE_BOARD, UPDATE_BOARD, ORBITDB_REPLICATE_PROGRESS, ORBITDB_REPLICATED, @@ -18,12 +19,18 @@ function updateBoard(existingBoards, address, value) { }) } +function deleteBoard(existingBoards, address) { + const boards = Object.assign({}, existingBoards) + delete boards[address] + return boards +} + export default function BoardsReducer(state = getInitialState(), action) { let address switch (action.type) { case OPENED_BOARD: address = action.board.address - return Object.assign({}, state, { boards: updateBoard(state.boards, address, action.board) }) + return Object.assign({}, state, { boards: updateBoard(state.boards, address, Object.assign({}, action.board, { open: true })) }) case UPDATE_BOARD: address = action.address let { posts, metadata } = action @@ -45,6 +52,11 @@ export default function BoardsReducer(state = getInitialState(), action) { replicating: false, lastReplicated: action.time })}) + case CLOSE_BOARD: + address = action.address + return Object.assign({}, state, { + boards: deleteBoard(state.boards, address) + }) default: return state; } diff --git a/src/sagas/boards.js b/src/sagas/boards.js index d2545ff..df10422 100644 --- a/src/sagas/boards.js +++ b/src/sagas/boards.js @@ -3,11 +3,14 @@ import { eventChannel } from 'redux-saga' import { push } from 'react-router-redux' import { open, connectDb } from '../orbitdb' import { createdBoard } from '../actions/board' -import { shortenAddress } from '../utils/orbitdb' +import { shortenAddress, closeBoard as closeOrbitDBBoard } from '../utils/orbitdb' import { UPDATE_BOARD } from '../actions/actionTypes' +import { saveSaga } from './persistence' export function* goToBoard({ board }){ - yield put(push(shortenAddress(board.address))) + if (board.redirect) { + yield put(push(shortenAddress(board.address))) + } } export function* updateBoard({ address }){ @@ -20,6 +23,11 @@ export function* updateBoard({ address }){ }) } +export function* closeBoard({ address }){ + yield call(closeOrbitDBBoard, address) + yield saveSaga() +} + export function* updateBoardMetadata({ address, metadata }){ const db = window.dbs[address] if (db) { @@ -47,7 +55,7 @@ export function* openBoard({ board }) { try { const channel = yield call(createDbEventChannel, db) yield fork(watchDb, channel) - yield put(createdBoard(Object.assign({}, board, dbInfo))) + yield put(createdBoard(Object.assign({ redirect: !!board.redirect }, board, dbInfo))) } catch (error) { yield put({ type: 'ERROR', error }) } diff --git a/src/sagas/index.js b/src/sagas/index.js index ca2a91f..596e128 100644 --- a/src/sagas/index.js +++ b/src/sagas/index.js @@ -1,15 +1,29 @@ -import { takeEvery } from 'redux-saga/effects' -import { OPEN_BOARD, OPENED_BOARD, ADD_POST, ORBITDB_REPLICATED, ORBITDB_WRITE, UPDATE_BOARD_METADATA } from '../actions/actionTypes' -import { openBoard, updateBoard, goToBoard, updateBoardMetadata } from './boards' +import { takeEvery, put, call } from 'redux-saga/effects' +import { + OPEN_BOARD, + OPENED_BOARD, + CLOSE_BOARD, + ADD_POST, + ORBITDB_REPLICATED, + ORBITDB_WRITE, + UPDATE_BOARD_METADATA +} from '../actions/actionTypes' +import { openBoard, updateBoard, goToBoard, updateBoardMetadata, closeBoard } from './boards' +import { openBoard as openBoardAction } from '../actions/board' import { addPost } from './posts' +import { openPreviousBoards, saveSaga } from './persistence' export default function* saga(){ yield takeEvery(OPEN_BOARD, openBoard) yield takeEvery(OPENED_BOARD, goToBoard) + yield takeEvery(OPENED_BOARD, saveSaga) + yield takeEvery(CLOSE_BOARD, closeBoard) yield takeEvery(ADD_POST, addPost) yield takeEvery(UPDATE_BOARD_METADATA, updateBoardMetadata) yield takeEvery(ORBITDB_WRITE, updateBoard) yield takeEvery(ORBITDB_REPLICATED, updateBoard) + + yield openPreviousBoards() } \ No newline at end of file diff --git a/src/sagas/persistence.js b/src/sagas/persistence.js new file mode 100644 index 0000000..f0df9a5 --- /dev/null +++ b/src/sagas/persistence.js @@ -0,0 +1,16 @@ +import { call, put } from 'redux-saga/effects' +import { openBoard } from '../actions/board' +import { save, load } from '../utils/persistence' + +export function* openPreviousBoards() { + const data = yield call(load) + if (Array.isArray(data.addresses)) { + for (const address of data.addresses) { + yield put(openBoard({ address, redirect: false })) + } + } +} + +export function* saveSaga() { + yield call(save) +} \ No newline at end of file diff --git a/src/utils/ipfs.js b/src/utils/ipfs.js index 2097b30..4b5de1d 100644 --- a/src/utils/ipfs.js +++ b/src/utils/ipfs.js @@ -17,7 +17,7 @@ export async function getStats() { const orbitDb = window.orbitDb const dbs = {} const stats = {} - if (ipfs) { + if (ipfs && ipfs.isOnline()) { stats.ipfsLoaded = true const peers = await ipfs.swarm.peers() const id = await ipfs.id() @@ -26,7 +26,7 @@ export async function getStats() { } else { stats.ipfsLoaded = false } - if (orbitDb) { + if (stats.ipfsLoaded && orbitDb) { stats.orbitDbLoaded = true stats.pubKey = await orbitDb.key.getPublic('hex') Object.values(window.dbs || {}).forEach(db => { diff --git a/src/utils/orbitdb.js b/src/utils/orbitdb.js index 31181cf..a8abc62 100644 --- a/src/utils/orbitdb.js +++ b/src/utils/orbitdb.js @@ -5,4 +5,10 @@ export function getBoardAddress(hash, name) { export function shortenAddress(address) { return address.replace(/^\/orbitdb/, '/b') +} + +export function closeBoard(address) { + const db = window.dbs[address] + delete window.dbs[address] + if (db && db.close) db.close() } \ No newline at end of file diff --git a/src/utils/persistence.js b/src/utils/persistence.js new file mode 100644 index 0000000..5a38b41 --- /dev/null +++ b/src/utils/persistence.js @@ -0,0 +1,16 @@ + +export function save(){ + const obj = { + addresses: Object.keys(window.dbs || {}) + } + localStorage.setItem('ipfs-boards-v0', JSON.stringify(obj)) +} + +export function load(){ + const str = localStorage.getItem('ipfs-boards-v0') + try { + return JSON.parse(str) || {}; + } catch (error) { + return {} + } +} \ No newline at end of file