mirror of https://github.com/nextcloud/bookmarks
Refactor vuex store
This commit is contained in:
parent
60cdafb5e0
commit
b0751b7dad
|
@ -3,7 +3,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mutations } from './store';
|
||||
import { mutations } from './store/';
|
||||
export default {
|
||||
name: 'App',
|
||||
computed: {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
import Vue from 'vue';
|
||||
import { Tooltip } from 'nextcloud-vue';
|
||||
import App from './components/ViewAdmin';
|
||||
import store from './store';
|
||||
import store from './store/';
|
||||
import AppGlobal from './mixins/AppGlobal';
|
||||
|
||||
Vue.mixin(AppGlobal);
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
import Vue from 'vue';
|
||||
import { Actions, ActionButton } from 'nextcloud-vue';
|
||||
import { generateUrl } from 'nextcloud-router';
|
||||
import { actions, mutations } from '../store';
|
||||
import { actions, mutations } from '../store/';
|
||||
import TagLine from './TagLine';
|
||||
|
||||
export default {
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
</template>
|
||||
<script>
|
||||
import { Multiselect, Actions, ActionButton } from 'nextcloud-vue';
|
||||
import { mutations } from '../store';
|
||||
import { mutations } from '../store/';
|
||||
|
||||
export default {
|
||||
name: 'Breadcrumbs',
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</template>
|
||||
<script>
|
||||
import { Actions, ActionButton } from 'nextcloud-vue';
|
||||
import { actions } from '../store';
|
||||
import { actions } from '../store/';
|
||||
export default {
|
||||
name: 'CreateBookmark',
|
||||
components: { Actions, ActionButton },
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</template>
|
||||
<script>
|
||||
import { Actions, ActionButton } from 'nextcloud-vue';
|
||||
import { actions } from '../store';
|
||||
import { actions } from '../store/';
|
||||
|
||||
export default {
|
||||
name: 'CreateFolder',
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
<script>
|
||||
import Vue from 'vue';
|
||||
import { Actions, ActionButton } from 'nextcloud-vue';
|
||||
import { actions, mutations } from '../store';
|
||||
import { actions, mutations } from '../store/';
|
||||
|
||||
export default {
|
||||
name: 'Folder',
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</template>
|
||||
<script>
|
||||
import { Modal } from 'nextcloud-vue';
|
||||
import { actions, mutations } from '../store';
|
||||
import { actions, mutations } from '../store/';
|
||||
import TreeFolder from './TreeFolder';
|
||||
|
||||
export default {
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
AppNavigationSettings
|
||||
} from 'nextcloud-vue';
|
||||
import Settings from './Settings';
|
||||
import { actions, mutations } from '../store';
|
||||
import { actions, mutations } from '../store/';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
</template>
|
||||
<script>
|
||||
import { generateUrl } from 'nextcloud-router';
|
||||
import { actions } from '../store';
|
||||
import { actions } from '../store/';
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {},
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
import { AppSidebar, AppSidebarTab, Multiselect } from 'nextcloud-vue';
|
||||
import { generateUrl } from 'nextcloud-router';
|
||||
import humanizeDuration from 'humanize-duration';
|
||||
import { actions, mutations } from '../store';
|
||||
import { actions, mutations } from '../store/';
|
||||
|
||||
const MAX_RELATIVE_DATE = 1000 * 60 * 60 * 24 * 7; // one week
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
<script>
|
||||
import { Content, Multiselect } from 'nextcloud-vue';
|
||||
import { actions } from '../store';
|
||||
import { actions } from '../store/';
|
||||
|
||||
export default {
|
||||
name: 'ViewBookmarklet',
|
||||
|
|
|
@ -17,7 +17,7 @@ import BookmarksList from './BookmarksList';
|
|||
import Breadcrumbs from './Breadcrumbs';
|
||||
import SidebarBookmark from './SidebarBookmark';
|
||||
import MoveDialog from './MoveDialog';
|
||||
import { actions } from '../store';
|
||||
import { actions } from '../store/';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
|
|
|
@ -23,7 +23,7 @@ import Vue from 'vue';
|
|||
import { Tooltip } from 'nextcloud-vue';
|
||||
import App from './App';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import store from './store/';
|
||||
import AppGlobal from './mixins/AppGlobal';
|
||||
|
||||
Vue.mixin(AppGlobal);
|
||||
|
|
776
src/store.js
776
src/store.js
|
@ -1,776 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import axios from 'nextcloud-axios';
|
||||
import { generateUrl } from 'nextcloud-router';
|
||||
import AppGlobal from './mixins/AppGlobal';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const BATCH_SIZE = 42;
|
||||
|
||||
export const mutations = {
|
||||
DISPLAY_NEW_BOOKMARK: 'DISPLAY_NEW_BOOKMARK',
|
||||
DISPLAY_NEW_FOLDER: 'DISPLAY_NEW_FOLDER',
|
||||
DISPLAY_MOVE_DIALOG: 'DISPLAY_MOVE_DIALOG',
|
||||
RESET_SELECTION: 'RESET_SELECTION',
|
||||
REMOVE_SELECTION_BOOKMARK: 'REMOVE_SELECTION_BOOKMARK',
|
||||
ADD_SELECTION_BOOKMARK: 'ADD_SELECTION_BOOKMARK',
|
||||
REMOVE_SELECTION_FOLDER: 'REMOVE_SELECTION_FOLDER',
|
||||
ADD_SELECTION_FOLDER: 'ADD_SELECTION_FOLDER',
|
||||
ADD_BOOKMARK: 'ADD_BOOKMARK',
|
||||
REMOVE_BOOKMARK: 'REMOVE_BOOKMARK',
|
||||
REMOVE_ALL_BOOKMARK: 'REMOVE_ALL_BOOKMARK',
|
||||
SET_TAGS: 'SET_TAGS',
|
||||
INCREMENT_PAGE: 'INCREMENT_PAGE',
|
||||
SET_QUERY: 'SET_QUERY',
|
||||
SET_SORTBY: 'SET_SORTBY',
|
||||
FETCH_START: 'FETCH_START',
|
||||
FETCH_END: 'FETCH_END',
|
||||
REACHED_END: 'REACHED_END',
|
||||
SET_ERROR: 'SET_ERROR',
|
||||
SET_FOLDERS: 'SET_FOLDERS',
|
||||
SET_SIDEBAR: 'SET_SIDEBAR',
|
||||
SET_SETTING: 'SET_SETTING',
|
||||
SET_VIEW_MODE: 'SET_VIEW_MODE'
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
ADD_ALL_BOOKMARKS: 'ADD_ALL_BOOKMARKS',
|
||||
CREATE_BOOKMARK: 'CREATE_BOOKMARK',
|
||||
FIND_BOOKMARK: 'FIND_BOOKMARK',
|
||||
DELETE_BOOKMARK: 'DELETE_BOOKMARK',
|
||||
OPEN_BOOKMARK: 'OPEN_BOOKMARK',
|
||||
SAVE_BOOKMARK: 'SAVE_BOOKMARK',
|
||||
MOVE_BOOKMARK: 'MOVE_BOOKMARK',
|
||||
IMPORT_BOOKMARKS: 'IMPORT_BOOKMARKS',
|
||||
DELETE_BOOKMARKS: 'IMPORT_BOOKMARKS',
|
||||
|
||||
LOAD_TAGS: 'LOAD_TAGS',
|
||||
RENAME_TAG: 'RENAME_TAG',
|
||||
DELETE_TAG: 'DELETE_TAG',
|
||||
|
||||
LOAD_FOLDERS: 'LOAD_FOLDERS',
|
||||
CREATE_FOLDER: 'CREATE_FOLDER',
|
||||
SAVE_FOLDER: 'SAVE_FOLDER',
|
||||
DELETE_FOLDER: 'DELETE_FOLDER',
|
||||
|
||||
MOVE_SELECTION: 'MOVE_SELECTION',
|
||||
|
||||
RELOAD_VIEW: 'RELOAD_VIEW',
|
||||
|
||||
NO_FILTER: 'NO_FILTER',
|
||||
FILTER_BY_RECENT: 'FILTER_BY_RECENT',
|
||||
FILTER_BY_UNTAGGED: 'FILTER_BY_UNTAGGED',
|
||||
FILTER_BY_TAGS: 'FILTER_BY_TAGS',
|
||||
FILTER_BY_FOLDER: 'FILTER_BY_FOLDER',
|
||||
FILTER_BY_SEARCH: 'FILTER_BY_SEARCH',
|
||||
FETCH_PAGE: 'FETCH_PAGE',
|
||||
|
||||
SET_SETTING: 'SET_SETTING',
|
||||
LOAD_SETTING: 'LOAD_SETTING',
|
||||
LOAD_SETTINGS: 'SLOAD_SETTINGS'
|
||||
};
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
fetchState: {
|
||||
page: 0,
|
||||
query: {},
|
||||
reachedEnd: false
|
||||
},
|
||||
loading: {
|
||||
tags: false,
|
||||
folders: false,
|
||||
bookmarks: false,
|
||||
createBookmark: false,
|
||||
saveBookmark: false,
|
||||
createFolder: false,
|
||||
saveFolder: false
|
||||
},
|
||||
error: null,
|
||||
settings: {
|
||||
viewMode: 'list',
|
||||
sorting: 'lastmodified'
|
||||
},
|
||||
bookmarks: [],
|
||||
bookmarksById: {},
|
||||
tags: [],
|
||||
folders: [],
|
||||
foldersById: {},
|
||||
selection: {
|
||||
folders: [],
|
||||
bookmarks: []
|
||||
},
|
||||
displayNewBookmark: false,
|
||||
displayNewFolder: false,
|
||||
displayMoveDialog: false,
|
||||
sidebar: null,
|
||||
viewMode: 'list'
|
||||
},
|
||||
|
||||
getters: {
|
||||
getBookmark: state => id => {
|
||||
return state.bookmarksById[id];
|
||||
},
|
||||
getFolder: state => id => {
|
||||
if (Number(id) === -1) {
|
||||
return [{ id: '-1', children: state.folders }];
|
||||
}
|
||||
return findFolder(id, state.folders);
|
||||
}
|
||||
},
|
||||
|
||||
mutations: {
|
||||
[mutations.SET_VIEW_MODE](state, viewMode) {
|
||||
state.viewMode = viewMode;
|
||||
},
|
||||
[mutations.SET_ERROR](state, error) {
|
||||
state.error = error;
|
||||
},
|
||||
[mutations.SET_SETTING](state, { key, value }) {
|
||||
Vue.set(state.settings, key, value);
|
||||
},
|
||||
[mutations.SET_FOLDERS](state, folders) {
|
||||
state.folders = folders;
|
||||
},
|
||||
[mutations.SET_TAGS](state, tags) {
|
||||
state.tags = tags;
|
||||
},
|
||||
[mutations.DISPLAY_NEW_BOOKMARK](state, display) {
|
||||
state.displayNewBookmark = display;
|
||||
if (display) {
|
||||
state.displayNewFolder = false;
|
||||
}
|
||||
},
|
||||
[mutations.DISPLAY_NEW_FOLDER](state, display) {
|
||||
state.displayNewFolder = display;
|
||||
if (display) {
|
||||
state.displayNewBookmark = false;
|
||||
}
|
||||
},
|
||||
[mutations.DISPLAY_MOVE_DIALOG](state, display) {
|
||||
state.displayMoveDialog = display;
|
||||
},
|
||||
|
||||
[mutations.RESET_SELECTION](state) {
|
||||
state.selection = { folders: [], bookmarks: [] };
|
||||
},
|
||||
[mutations.ADD_SELECTION_BOOKMARK](state, item) {
|
||||
state.selection.bookmarks.push(item);
|
||||
},
|
||||
[mutations.REMOVE_SELECTION_BOOKMARK](state, item) {
|
||||
Vue.set(
|
||||
state.selection,
|
||||
'bookmarks',
|
||||
state.selection.bookmarks.filter(s => !(s.id === item.id))
|
||||
);
|
||||
},
|
||||
[mutations.ADD_SELECTION_FOLDER](state, item) {
|
||||
state.selection.folders.push(item);
|
||||
},
|
||||
[mutations.REMOVE_SELECTION_FOLDER](state, item) {
|
||||
Vue.set(
|
||||
state.selection,
|
||||
'folders',
|
||||
state.selection.folders.filter(s => !(s.id === item.id))
|
||||
);
|
||||
},
|
||||
|
||||
[mutations.ADD_BOOKMARK](state, bookmark) {
|
||||
const existingBookmark = state.bookmarksById[bookmark.id];
|
||||
if (!existingBookmark) {
|
||||
state.bookmarks.push(bookmark);
|
||||
Vue.set(state.bookmarksById, bookmark.id, bookmark);
|
||||
}
|
||||
},
|
||||
[mutations.REMOVE_BOOKMARK](state, id) {
|
||||
const index = state.bookmarks.findIndex(bookmark => bookmark.id === id);
|
||||
if (index !== -1) {
|
||||
state.bookmarks.splice(index, 1);
|
||||
Vue.delete(state.bookmarksById, id);
|
||||
}
|
||||
},
|
||||
[mutations.REMOVE_ALL_BOOKMARKS](state) {
|
||||
state.bookmarks = [];
|
||||
state.bookmarksById = {};
|
||||
},
|
||||
|
||||
[mutations.SET_SIDEBAR](state, sidebar) {
|
||||
state.sidebar = sidebar;
|
||||
},
|
||||
|
||||
[mutations.INCREMENT_PAGE](state) {
|
||||
Vue.set(state.fetchState, 'page', state.fetchState.page + 1);
|
||||
},
|
||||
[mutations.SET_QUERY](state, query) {
|
||||
state.bookmarks = [];
|
||||
state.bookmarksById = {};
|
||||
Vue.set(state.fetchState, 'page', 0);
|
||||
Vue.set(state.fetchState, 'reachedEnd', false);
|
||||
Vue.set(state.fetchState, 'query', query);
|
||||
},
|
||||
[mutations.FETCH_START](state, type) {
|
||||
Vue.set(state.loading, type, true);
|
||||
},
|
||||
[mutations.FETCH_END](state, type) {
|
||||
Vue.set(state.loading, type, false);
|
||||
},
|
||||
|
||||
[mutations.REACHED_END](state) {
|
||||
Vue.set(state.fetchState, 'reachedEnd', true);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
[actions.ADD_ALL_BOOKMARKS]({ commit }, bookmarks) {
|
||||
for (const bookmark of bookmarks) {
|
||||
commit(mutations.ADD_BOOKMARK, bookmark);
|
||||
}
|
||||
},
|
||||
|
||||
async [actions.FIND_BOOKMARK]({ commit, dispatch, state }, link) {
|
||||
if (state.loading.bookmarks) return;
|
||||
try {
|
||||
const response = await axios
|
||||
.get(url('/bookmark'), { params: {
|
||||
url: link
|
||||
} });
|
||||
const {
|
||||
data: { data: bookmarks, status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
if (!bookmarks.length) return;
|
||||
commit(mutations.ADD_BOOKMARK, bookmarks[0]);
|
||||
return bookmarks[0];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to find existing bookmark')
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
[actions.CREATE_BOOKMARK]({ commit, dispatch, state }, data) {
|
||||
if (state.loading.bookmarks) return;
|
||||
commit(mutations.FETCH_START, 'createBookmark');
|
||||
return axios
|
||||
.post(url('/bookmark'), {
|
||||
url: data.url,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
folders: data.folders,
|
||||
tags: data.tags
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { item: bookmark, status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.DISPLAY_NEW_BOOKMARK, false);
|
||||
commit(mutations.ADD_BOOKMARK, bookmark);
|
||||
return dispatch(actions.OPEN_BOOKMARK, bookmark.id);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create bookmark')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'createBookmark');
|
||||
});
|
||||
},
|
||||
[actions.SAVE_BOOKMARK]({ commit, dispatch, state }, id) {
|
||||
commit(mutations.FETCH_START, 'saveBookmark');
|
||||
return axios
|
||||
.put(url(`/bookmark/${id}`), this.getters.getBookmark(id))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to save bookmark')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'saveBookmark');
|
||||
});
|
||||
},
|
||||
async [actions.MOVE_BOOKMARK](
|
||||
{ commit, dispatch, state },
|
||||
{ bookmark, oldFolder, newFolder }
|
||||
) {
|
||||
commit(mutations.FETCH_START, 'moveBookmark');
|
||||
try {
|
||||
let response = await axios.post(
|
||||
url(`/folder/${newFolder}/bookmarks/${bookmark}`)
|
||||
);
|
||||
if (response.data.status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
let response2 = await axios.delete(
|
||||
url(`/folder/${oldFolder}/bookmarks/${bookmark}`)
|
||||
);
|
||||
if (response2.data.status !== 'success') {
|
||||
throw new Error(response2.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to move bookmark')
|
||||
);
|
||||
throw err;
|
||||
} finally {
|
||||
commit(mutations.FETCH_END, 'moveBookmark');
|
||||
}
|
||||
},
|
||||
[actions.OPEN_BOOKMARK]({ commit }, id) {
|
||||
commit(mutations.SET_SIDEBAR, { type: 'bookmark', id });
|
||||
},
|
||||
async [actions.DELETE_BOOKMARK](
|
||||
{ commit, dispatch, state },
|
||||
{ id, folder }
|
||||
) {
|
||||
if (folder) {
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
url(`/folder/${folder}/bookmarks/${id}`)
|
||||
);
|
||||
if (response.data.status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.REMOVE_BOOKMARK, id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete bookmark')
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.delete(url(`/bookmark/${id}`));
|
||||
if (response.data.status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.REMOVE_BOOKMARK, id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete bookmark')
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
[actions.IMPORT_BOOKMARKS]({ commit, dispatch, state }, file) {
|
||||
var data = new FormData();
|
||||
data.append('bm_import', file);
|
||||
return axios
|
||||
.post(url(`/bookmark/import`), data)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
if (response.status === 413) {
|
||||
throw new Error('Selected file is too large');
|
||||
}
|
||||
throw new Error(response.statusText);
|
||||
} else {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', err.message)
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.DELETE_BOOKMARKS]({ commit, dispatch, state }) {
|
||||
return axios
|
||||
.delete(url(`/bookmark`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
return dispatch(actions.LOAD_FOLDERS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', err.message)
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
[actions.RENAME_TAG]({ commit, dispatch, state }, { oldName, newName }) {
|
||||
commit(mutations.FETCH_START, 'tag');
|
||||
return axios
|
||||
.put(url(`/tag/${oldName}`), {
|
||||
name: newName
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
return dispatch(actions.LOAD_TAGS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create bookmark')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'tag');
|
||||
});
|
||||
},
|
||||
[actions.LOAD_TAGS]({ commit, dispatch, state }, link) {
|
||||
if (state.loading.bookmarks) return;
|
||||
commit(mutations.FETCH_START, 'tags');
|
||||
return axios
|
||||
.get(url('/tag'), { params: { count: true } })
|
||||
.then(response => {
|
||||
const { data: tags } = response;
|
||||
return commit(mutations.SET_TAGS, tags);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to load tags')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'tags');
|
||||
});
|
||||
},
|
||||
[actions.DELETE_TAG]({ commit, dispatch, state }, tag) {
|
||||
return axios
|
||||
.delete(url(`/tag/${tag}`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
dispatch(actions.LOAD_TAGS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete bookmark')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
[actions.LOAD_FOLDERS]({ commit, dispatch, state }) {
|
||||
if (state.loading.bookmarks) return;
|
||||
commit(mutations.FETCH_START, 'folders');
|
||||
return axios
|
||||
.get(url('/folder'), { params: {} })
|
||||
.then(response => {
|
||||
const {
|
||||
data: { data, status }
|
||||
} = response;
|
||||
if (status !== 'success') throw new Error(data);
|
||||
const folders = data;
|
||||
return commit(mutations.SET_FOLDERS, folders);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to load folders')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'folders');
|
||||
});
|
||||
},
|
||||
[actions.DELETE_FOLDER]({ commit, dispatch, state }, id) {
|
||||
return axios
|
||||
.delete(url(`/folder/${id}`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
dispatch(actions.LOAD_FOLDERS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete folder')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.CREATE_FOLDER](
|
||||
{ commit, dispatch, state },
|
||||
{ parentFolder, title }
|
||||
) {
|
||||
return axios
|
||||
.post(url(`/folder`), {
|
||||
parent_folder: parentFolder,
|
||||
title
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.DISPLAY_NEW_FOLDER, false);
|
||||
dispatch(actions.LOAD_FOLDERS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create folder')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.SAVE_FOLDER]({ commit, dispatch, state }, id) {
|
||||
const folder = this.getters.getFolder(id)[0];
|
||||
commit(mutations.FETCH_START, 'saveFolder');
|
||||
return axios
|
||||
.put(url(`/folder/${id}`), {
|
||||
parent_folder: folder.parent_folder,
|
||||
title: folder.title
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create folder')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'saveFolder');
|
||||
});
|
||||
},
|
||||
|
||||
async [actions.MOVE_SELECTION]({ commit, dispatch, state }, folderId) {
|
||||
commit(mutations.FETCH_START, 'moveSelection');
|
||||
try {
|
||||
for (const folder of state.selection.folders) {
|
||||
if (folderId === folder.id) {
|
||||
throw new Error('Cannot move folder into itself');
|
||||
}
|
||||
folder.parent_folder = folderId;
|
||||
await dispatch(actions.SAVE_FOLDER, folder.id);
|
||||
}
|
||||
|
||||
for (const bookmark of state.selection.bookmarks) {
|
||||
await dispatch(actions.MOVE_BOOKMARK, {
|
||||
oldFolder: bookmark.folders[bookmark.folders.length - 1], // FIXME This is veeeery ugly and will cause issues. Inevitably.
|
||||
newFolder: folderId,
|
||||
bookmark: bookmark.id
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to move parts of selection')
|
||||
);
|
||||
throw err;
|
||||
} finally {
|
||||
commit(mutations.FETCH_END, 'moveSelection');
|
||||
}
|
||||
},
|
||||
|
||||
[actions.RELOAD_VIEW]({ state, dispatch, commit }) {
|
||||
commit(mutations.SET_QUERY, state.fetchState.query);
|
||||
dispatch(actions.FETCH_PAGE);
|
||||
dispatch(actions.LOAD_FOLDERS);
|
||||
dispatch(actions.LOAD_TAGS);
|
||||
},
|
||||
|
||||
[actions.NO_FILTER]({ dispatch, commit }) {
|
||||
commit(mutations.SET_QUERY, {});
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_RECENT]({ dispatch, commit }, search) {
|
||||
commit(mutations.SET_QUERY, { sortby: 'lastmodified' });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_SEARCH]({ dispatch, commit }, search) {
|
||||
commit(mutations.SET_QUERY, { search: search.split(' ') });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_TAGS]({ dispatch, commit }, tags) {
|
||||
commit(mutations.SET_QUERY, { tags, conjunction: 'and' });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_UNTAGGED]({ dispatch, commit }) {
|
||||
commit(mutations.SET_QUERY, { untagged: true });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_FOLDER]({ dispatch, commit }, folder) {
|
||||
commit(mutations.SET_QUERY, { folder });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FETCH_PAGE]({ dispatch, commit, state }) {
|
||||
if (state.loading.bookmarks) return;
|
||||
if (state.fetchState.reachedEnd) return;
|
||||
commit(mutations.FETCH_START, 'bookmarks');
|
||||
return axios
|
||||
.get(url('/bookmark'), {
|
||||
params: {
|
||||
limit: BATCH_SIZE,
|
||||
page: state.fetchState.page,
|
||||
sortby: state.settings.sorting,
|
||||
...state.fetchState.query
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { data, status }
|
||||
} = response;
|
||||
if (status !== 'success') throw new Error(data);
|
||||
const bookmarks = data;
|
||||
commit(mutations.INCREMENT_PAGE);
|
||||
if (bookmarks.length < BATCH_SIZE) {
|
||||
commit(mutations.REACHED_END);
|
||||
}
|
||||
return dispatch(actions.ADD_ALL_BOOKMARKS, bookmarks);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.t('bookmarks', 'Failed to fetch bookmarks.')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'bookmarks');
|
||||
});
|
||||
},
|
||||
|
||||
[actions.SET_SETTING]({ commit, dispatch, state }, { key, value }) {
|
||||
return axios
|
||||
.post(url(`/settings/${key}`), {
|
||||
[key]: value
|
||||
})
|
||||
.then(response => {
|
||||
commit(mutations.SET_SETTING, key, value);
|
||||
if (key === 'viewMode' && state.viewMode !== value) {
|
||||
commit(mutations.SET_VIEW_MODE, value);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to change setting')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.LOAD_SETTING]({ commit, dispatch, state }, key) {
|
||||
return axios
|
||||
.get(url(`/settings/${key}`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { [key]: value }
|
||||
} = response;
|
||||
commit(mutations.SET_SETTING, { key, value });
|
||||
if (key === 'viewMode' && state.viewMode !== value) {
|
||||
commit(mutations.SET_VIEW_MODE, value);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to load setting ' + key)
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.LOAD_SETTINGS]({ commit, dispatch, state }) {
|
||||
return Promise.all(
|
||||
['sorting', 'viewMode'].map(key => dispatch(actions.LOAD_SETTING, key))
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function url(url) {
|
||||
url = `/apps/bookmarks${url}`;
|
||||
return generateUrl(url);
|
||||
}
|
||||
|
||||
function findFolder(id, children) {
|
||||
if (!children || !children.length) return [];
|
||||
let folders = children.filter(folder => Number(folder.id) === Number(id));
|
||||
if (folders.length) {
|
||||
return folders;
|
||||
} else {
|
||||
for (let child of children) {
|
||||
let folders = findFolder(id, child.children);
|
||||
if (folders.length) {
|
||||
folders.push(child);
|
||||
return folders;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,580 @@
|
|||
import axios from 'nextcloud-axios';
|
||||
import { generateUrl } from 'nextcloud-router';
|
||||
import AppGlobal from '../mixins/AppGlobal';
|
||||
import { mutations } from './mutations';
|
||||
|
||||
const BATCH_SIZE = 42;
|
||||
|
||||
export const actions = {
|
||||
ADD_ALL_BOOKMARKS: 'ADD_ALL_BOOKMARKS',
|
||||
CREATE_BOOKMARK: 'CREATE_BOOKMARK',
|
||||
FIND_BOOKMARK: 'FIND_BOOKMARK',
|
||||
DELETE_BOOKMARK: 'DELETE_BOOKMARK',
|
||||
OPEN_BOOKMARK: 'OPEN_BOOKMARK',
|
||||
SAVE_BOOKMARK: 'SAVE_BOOKMARK',
|
||||
MOVE_BOOKMARK: 'MOVE_BOOKMARK',
|
||||
IMPORT_BOOKMARKS: 'IMPORT_BOOKMARKS',
|
||||
DELETE_BOOKMARKS: 'IMPORT_BOOKMARKS',
|
||||
|
||||
LOAD_TAGS: 'LOAD_TAGS',
|
||||
RENAME_TAG: 'RENAME_TAG',
|
||||
DELETE_TAG: 'DELETE_TAG',
|
||||
|
||||
LOAD_FOLDERS: 'LOAD_FOLDERS',
|
||||
CREATE_FOLDER: 'CREATE_FOLDER',
|
||||
SAVE_FOLDER: 'SAVE_FOLDER',
|
||||
DELETE_FOLDER: 'DELETE_FOLDER',
|
||||
|
||||
MOVE_SELECTION: 'MOVE_SELECTION',
|
||||
|
||||
RELOAD_VIEW: 'RELOAD_VIEW',
|
||||
|
||||
NO_FILTER: 'NO_FILTER',
|
||||
FILTER_BY_RECENT: 'FILTER_BY_RECENT',
|
||||
FILTER_BY_UNTAGGED: 'FILTER_BY_UNTAGGED',
|
||||
FILTER_BY_TAGS: 'FILTER_BY_TAGS',
|
||||
FILTER_BY_FOLDER: 'FILTER_BY_FOLDER',
|
||||
FILTER_BY_SEARCH: 'FILTER_BY_SEARCH',
|
||||
FETCH_PAGE: 'FETCH_PAGE',
|
||||
|
||||
SET_SETTING: 'SET_SETTING',
|
||||
LOAD_SETTING: 'LOAD_SETTING',
|
||||
LOAD_SETTINGS: 'SLOAD_SETTINGS'
|
||||
};
|
||||
|
||||
export default {
|
||||
[actions.ADD_ALL_BOOKMARKS]({ commit }, bookmarks) {
|
||||
for (const bookmark of bookmarks) {
|
||||
commit(mutations.ADD_BOOKMARK, bookmark);
|
||||
}
|
||||
},
|
||||
|
||||
async [actions.FIND_BOOKMARK]({ commit, dispatch, state }, link) {
|
||||
if (state.loading.bookmarks) return;
|
||||
try {
|
||||
const response = await axios
|
||||
.get(url('/bookmark'), { params: {
|
||||
url: link
|
||||
} });
|
||||
const {
|
||||
data: { data: bookmarks, status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
if (!bookmarks.length) return;
|
||||
commit(mutations.ADD_BOOKMARK, bookmarks[0]);
|
||||
return bookmarks[0];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to find existing bookmark')
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
[actions.CREATE_BOOKMARK]({ commit, dispatch, state }, data) {
|
||||
if (state.loading.bookmarks) return;
|
||||
commit(mutations.FETCH_START, 'createBookmark');
|
||||
return axios
|
||||
.post(url('/bookmark'), {
|
||||
url: data.url,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
folders: data.folders,
|
||||
tags: data.tags
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { item: bookmark, status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.DISPLAY_NEW_BOOKMARK, false);
|
||||
commit(mutations.ADD_BOOKMARK, bookmark);
|
||||
return dispatch(actions.OPEN_BOOKMARK, bookmark.id);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create bookmark')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'createBookmark');
|
||||
});
|
||||
},
|
||||
[actions.SAVE_BOOKMARK]({ commit, dispatch, state }, id) {
|
||||
commit(mutations.FETCH_START, 'saveBookmark');
|
||||
return axios
|
||||
.put(url(`/bookmark/${id}`), this.getters.getBookmark(id))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to save bookmark')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'saveBookmark');
|
||||
});
|
||||
},
|
||||
async [actions.MOVE_BOOKMARK](
|
||||
{ commit, dispatch, state },
|
||||
{ bookmark, oldFolder, newFolder }
|
||||
) {
|
||||
commit(mutations.FETCH_START, 'moveBookmark');
|
||||
try {
|
||||
let response = await axios.post(
|
||||
url(`/folder/${newFolder}/bookmarks/${bookmark}`)
|
||||
);
|
||||
if (response.data.status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
let response2 = await axios.delete(
|
||||
url(`/folder/${oldFolder}/bookmarks/${bookmark}`)
|
||||
);
|
||||
if (response2.data.status !== 'success') {
|
||||
throw new Error(response2.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to move bookmark')
|
||||
);
|
||||
throw err;
|
||||
} finally {
|
||||
commit(mutations.FETCH_END, 'moveBookmark');
|
||||
}
|
||||
},
|
||||
[actions.OPEN_BOOKMARK]({ commit }, id) {
|
||||
commit(mutations.SET_SIDEBAR, { type: 'bookmark', id });
|
||||
},
|
||||
async [actions.DELETE_BOOKMARK](
|
||||
{ commit, dispatch, state },
|
||||
{ id, folder }
|
||||
) {
|
||||
if (folder) {
|
||||
try {
|
||||
const response = await axios.delete(
|
||||
url(`/folder/${folder}/bookmarks/${id}`)
|
||||
);
|
||||
if (response.data.status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.REMOVE_BOOKMARK, id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete bookmark')
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await axios.delete(url(`/bookmark/${id}`));
|
||||
if (response.data.status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.REMOVE_BOOKMARK, id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete bookmark')
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
[actions.IMPORT_BOOKMARKS]({ commit, dispatch, state }, file) {
|
||||
var data = new FormData();
|
||||
data.append('bm_import', file);
|
||||
return axios
|
||||
.post(url(`/bookmark/import`), data)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
if (response.status === 413) {
|
||||
throw new Error('Selected file is too large');
|
||||
}
|
||||
throw new Error(response.statusText);
|
||||
} else {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', err.message)
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.DELETE_BOOKMARKS]({ commit, dispatch, state }) {
|
||||
return axios
|
||||
.delete(url(`/bookmark`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
return dispatch(actions.LOAD_FOLDERS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', err.message)
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
[actions.RENAME_TAG]({ commit, dispatch, state }, { oldName, newName }) {
|
||||
commit(mutations.FETCH_START, 'tag');
|
||||
return axios
|
||||
.put(url(`/tag/${oldName}`), {
|
||||
name: newName
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
return dispatch(actions.LOAD_TAGS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create bookmark')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'tag');
|
||||
});
|
||||
},
|
||||
[actions.LOAD_TAGS]({ commit, dispatch, state }, link) {
|
||||
if (state.loading.bookmarks) return;
|
||||
commit(mutations.FETCH_START, 'tags');
|
||||
return axios
|
||||
.get(url('/tag'), { params: { count: true } })
|
||||
.then(response => {
|
||||
const { data: tags } = response;
|
||||
return commit(mutations.SET_TAGS, tags);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to load tags')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'tags');
|
||||
});
|
||||
},
|
||||
[actions.DELETE_TAG]({ commit, dispatch, state }, tag) {
|
||||
return axios
|
||||
.delete(url(`/tag/${tag}`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
dispatch(actions.LOAD_TAGS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete bookmark')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
[actions.LOAD_FOLDERS]({ commit, dispatch, state }) {
|
||||
if (state.loading.bookmarks) return;
|
||||
commit(mutations.FETCH_START, 'folders');
|
||||
return axios
|
||||
.get(url('/folder'), { params: {} })
|
||||
.then(response => {
|
||||
const {
|
||||
data: { data, status }
|
||||
} = response;
|
||||
if (status !== 'success') throw new Error(data);
|
||||
const folders = data;
|
||||
return commit(mutations.SET_FOLDERS, folders);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to load folders')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'folders');
|
||||
});
|
||||
},
|
||||
[actions.DELETE_FOLDER]({ commit, dispatch, state }, id) {
|
||||
return axios
|
||||
.delete(url(`/folder/${id}`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
dispatch(actions.LOAD_FOLDERS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to delete folder')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.CREATE_FOLDER](
|
||||
{ commit, dispatch, state },
|
||||
{ parentFolder, title }
|
||||
) {
|
||||
return axios
|
||||
.post(url(`/folder`), {
|
||||
parent_folder: parentFolder,
|
||||
title
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
commit(mutations.DISPLAY_NEW_FOLDER, false);
|
||||
dispatch(actions.LOAD_FOLDERS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create folder')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.SAVE_FOLDER]({ commit, dispatch, state }, id) {
|
||||
const folder = this.getters.getFolder(id)[0];
|
||||
commit(mutations.FETCH_START, 'saveFolder');
|
||||
return axios
|
||||
.put(url(`/folder/${id}`), {
|
||||
parent_folder: folder.parent_folder,
|
||||
title: folder.title
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { status }
|
||||
} = response;
|
||||
if (status !== 'success') {
|
||||
throw new Error(response.data);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to create folder')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'saveFolder');
|
||||
});
|
||||
},
|
||||
|
||||
async [actions.MOVE_SELECTION]({ commit, dispatch, state }, folderId) {
|
||||
commit(mutations.FETCH_START, 'moveSelection');
|
||||
try {
|
||||
for (const folder of state.selection.folders) {
|
||||
if (folderId === folder.id) {
|
||||
throw new Error('Cannot move folder into itself');
|
||||
}
|
||||
folder.parent_folder = folderId;
|
||||
await dispatch(actions.SAVE_FOLDER, folder.id);
|
||||
}
|
||||
|
||||
for (const bookmark of state.selection.bookmarks) {
|
||||
await dispatch(actions.MOVE_BOOKMARK, {
|
||||
oldFolder: bookmark.folders[bookmark.folders.length - 1], // FIXME This is veeeery ugly and will cause issues. Inevitably.
|
||||
newFolder: folderId,
|
||||
bookmark: bookmark.id
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to move parts of selection')
|
||||
);
|
||||
throw err;
|
||||
} finally {
|
||||
commit(mutations.FETCH_END, 'moveSelection');
|
||||
}
|
||||
},
|
||||
|
||||
[actions.RELOAD_VIEW]({ state, dispatch, commit }) {
|
||||
commit(mutations.SET_QUERY, state.fetchState.query);
|
||||
dispatch(actions.FETCH_PAGE);
|
||||
dispatch(actions.LOAD_FOLDERS);
|
||||
dispatch(actions.LOAD_TAGS);
|
||||
},
|
||||
|
||||
[actions.NO_FILTER]({ dispatch, commit }) {
|
||||
commit(mutations.SET_QUERY, {});
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_RECENT]({ dispatch, commit }, search) {
|
||||
commit(mutations.SET_QUERY, { sortby: 'lastmodified' });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_SEARCH]({ dispatch, commit }, search) {
|
||||
commit(mutations.SET_QUERY, { search: search.split(' ') });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_TAGS]({ dispatch, commit }, tags) {
|
||||
commit(mutations.SET_QUERY, { tags, conjunction: 'and' });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_UNTAGGED]({ dispatch, commit }) {
|
||||
commit(mutations.SET_QUERY, { untagged: true });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FILTER_BY_FOLDER]({ dispatch, commit }, folder) {
|
||||
commit(mutations.SET_QUERY, { folder });
|
||||
return dispatch(actions.FETCH_PAGE);
|
||||
},
|
||||
[actions.FETCH_PAGE]({ dispatch, commit, state }) {
|
||||
if (state.loading.bookmarks) return;
|
||||
if (state.fetchState.reachedEnd) return;
|
||||
commit(mutations.FETCH_START, 'bookmarks');
|
||||
return axios
|
||||
.get(url('/bookmark'), {
|
||||
params: {
|
||||
limit: BATCH_SIZE,
|
||||
page: state.fetchState.page,
|
||||
sortby: state.settings.sorting,
|
||||
...state.fetchState.query
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
const {
|
||||
data: { data, status }
|
||||
} = response;
|
||||
if (status !== 'success') throw new Error(data);
|
||||
const bookmarks = data;
|
||||
commit(mutations.INCREMENT_PAGE);
|
||||
if (bookmarks.length < BATCH_SIZE) {
|
||||
commit(mutations.REACHED_END);
|
||||
}
|
||||
return dispatch(actions.ADD_ALL_BOOKMARKS, bookmarks);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.t('bookmarks', 'Failed to fetch bookmarks.')
|
||||
);
|
||||
throw err;
|
||||
})
|
||||
.finally(() => {
|
||||
commit(mutations.FETCH_END, 'bookmarks');
|
||||
});
|
||||
},
|
||||
|
||||
[actions.SET_SETTING]({ commit, dispatch, state }, { key, value }) {
|
||||
return axios
|
||||
.post(url(`/settings/${key}`), {
|
||||
[key]: value
|
||||
})
|
||||
.then(response => {
|
||||
commit(mutations.SET_SETTING, key, value);
|
||||
if (key === 'viewMode' && state.viewMode !== value) {
|
||||
commit(mutations.SET_VIEW_MODE, value);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to change setting')
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.LOAD_SETTING]({ commit, dispatch, state }, key) {
|
||||
return axios
|
||||
.get(url(`/settings/${key}`))
|
||||
.then(response => {
|
||||
const {
|
||||
data: { [key]: value }
|
||||
} = response;
|
||||
commit(mutations.SET_SETTING, { key, value });
|
||||
if (key === 'viewMode' && state.viewMode !== value) {
|
||||
commit(mutations.SET_VIEW_MODE, value);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
commit(
|
||||
mutations.SET_ERROR,
|
||||
AppGlobal.methods.t('bookmarks', 'Failed to load setting ' + key)
|
||||
);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
[actions.LOAD_SETTINGS]({ commit, dispatch, state }) {
|
||||
return Promise.all(
|
||||
['sorting', 'viewMode'].map(key => dispatch(actions.LOAD_SETTING, key))
|
||||
);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
function url(url) {
|
||||
url = `/apps/bookmarks${url}`;
|
||||
return generateUrl(url);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex, { Store } from 'vuex';
|
||||
import Mutations from './mutations';
|
||||
import Actions from './actions';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
export { mutations } from './mutations';
|
||||
|
||||
export { actions } from './actions';
|
||||
|
||||
export default new Store({
|
||||
mutations: Mutations,
|
||||
actions: Actions,
|
||||
state: {
|
||||
fetchState: {
|
||||
page: 0,
|
||||
query: {},
|
||||
reachedEnd: false
|
||||
},
|
||||
loading: {
|
||||
tags: false,
|
||||
folders: false,
|
||||
bookmarks: false,
|
||||
createBookmark: false,
|
||||
saveBookmark: false,
|
||||
createFolder: false,
|
||||
saveFolder: false
|
||||
},
|
||||
error: null,
|
||||
settings: {
|
||||
viewMode: 'list',
|
||||
sorting: 'lastmodified'
|
||||
},
|
||||
bookmarks: [],
|
||||
bookmarksById: {},
|
||||
tags: [],
|
||||
folders: [],
|
||||
foldersById: {},
|
||||
selection: {
|
||||
folders: [],
|
||||
bookmarks: []
|
||||
},
|
||||
displayNewBookmark: false,
|
||||
displayNewFolder: false,
|
||||
displayMoveDialog: false,
|
||||
sidebar: null,
|
||||
viewMode: 'list'
|
||||
},
|
||||
|
||||
getters: {
|
||||
getBookmark: state => id => {
|
||||
return state.bookmarksById[id];
|
||||
},
|
||||
getFolder: state => id => {
|
||||
if (Number(id) === -1) {
|
||||
return [{ id: '-1', children: state.folders }];
|
||||
}
|
||||
return findFolder(id, state.folders);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function findFolder(id, children) {
|
||||
if (!children || !children.length) return [];
|
||||
let folders = children.filter(folder => Number(folder.id) === Number(id));
|
||||
if (folders.length) {
|
||||
return folders;
|
||||
} else {
|
||||
for (let child of children) {
|
||||
let folders = findFolder(id, child.children);
|
||||
if (folders.length) {
|
||||
folders.push(child);
|
||||
return folders;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
export const mutations = {
|
||||
DISPLAY_NEW_BOOKMARK: 'DISPLAY_NEW_BOOKMARK',
|
||||
DISPLAY_NEW_FOLDER: 'DISPLAY_NEW_FOLDER',
|
||||
DISPLAY_MOVE_DIALOG: 'DISPLAY_MOVE_DIALOG',
|
||||
RESET_SELECTION: 'RESET_SELECTION',
|
||||
REMOVE_SELECTION_BOOKMARK: 'REMOVE_SELECTION_BOOKMARK',
|
||||
ADD_SELECTION_BOOKMARK: 'ADD_SELECTION_BOOKMARK',
|
||||
REMOVE_SELECTION_FOLDER: 'REMOVE_SELECTION_FOLDER',
|
||||
ADD_SELECTION_FOLDER: 'ADD_SELECTION_FOLDER',
|
||||
ADD_BOOKMARK: 'ADD_BOOKMARK',
|
||||
REMOVE_BOOKMARK: 'REMOVE_BOOKMARK',
|
||||
REMOVE_ALL_BOOKMARK: 'REMOVE_ALL_BOOKMARK',
|
||||
SET_TAGS: 'SET_TAGS',
|
||||
INCREMENT_PAGE: 'INCREMENT_PAGE',
|
||||
SET_QUERY: 'SET_QUERY',
|
||||
SET_SORTBY: 'SET_SORTBY',
|
||||
FETCH_START: 'FETCH_START',
|
||||
FETCH_END: 'FETCH_END',
|
||||
REACHED_END: 'REACHED_END',
|
||||
SET_ERROR: 'SET_ERROR',
|
||||
SET_FOLDERS: 'SET_FOLDERS',
|
||||
SET_SIDEBAR: 'SET_SIDEBAR',
|
||||
SET_SETTING: 'SET_SETTING',
|
||||
SET_VIEW_MODE: 'SET_VIEW_MODE'
|
||||
};
|
||||
export default {
|
||||
[mutations.SET_VIEW_MODE](state, viewMode) {
|
||||
state.viewMode = viewMode;
|
||||
},
|
||||
[mutations.SET_ERROR](state, error) {
|
||||
state.error = error;
|
||||
},
|
||||
[mutations.SET_SETTING](state, { key, value }) {
|
||||
Vue.set(state.settings, key, value);
|
||||
},
|
||||
[mutations.SET_FOLDERS](state, folders) {
|
||||
state.folders = folders;
|
||||
},
|
||||
[mutations.SET_TAGS](state, tags) {
|
||||
state.tags = tags;
|
||||
},
|
||||
[mutations.DISPLAY_NEW_BOOKMARK](state, display) {
|
||||
state.displayNewBookmark = display;
|
||||
if (display) {
|
||||
state.displayNewFolder = false;
|
||||
}
|
||||
},
|
||||
[mutations.DISPLAY_NEW_FOLDER](state, display) {
|
||||
state.displayNewFolder = display;
|
||||
if (display) {
|
||||
state.displayNewBookmark = false;
|
||||
}
|
||||
},
|
||||
[mutations.DISPLAY_MOVE_DIALOG](state, display) {
|
||||
state.displayMoveDialog = display;
|
||||
},
|
||||
|
||||
[mutations.RESET_SELECTION](state) {
|
||||
state.selection = { folders: [], bookmarks: [] };
|
||||
},
|
||||
[mutations.ADD_SELECTION_BOOKMARK](state, item) {
|
||||
state.selection.bookmarks.push(item);
|
||||
},
|
||||
[mutations.REMOVE_SELECTION_BOOKMARK](state, item) {
|
||||
Vue.set(
|
||||
state.selection,
|
||||
'bookmarks',
|
||||
state.selection.bookmarks.filter(s => !(s.id === item.id))
|
||||
);
|
||||
},
|
||||
[mutations.ADD_SELECTION_FOLDER](state, item) {
|
||||
state.selection.folders.push(item);
|
||||
},
|
||||
[mutations.REMOVE_SELECTION_FOLDER](state, item) {
|
||||
Vue.set(
|
||||
state.selection,
|
||||
'folders',
|
||||
state.selection.folders.filter(s => !(s.id === item.id))
|
||||
);
|
||||
},
|
||||
|
||||
[mutations.ADD_BOOKMARK](state, bookmark) {
|
||||
const existingBookmark = state.bookmarksById[bookmark.id];
|
||||
if (!existingBookmark) {
|
||||
state.bookmarks.push(bookmark);
|
||||
Vue.set(state.bookmarksById, bookmark.id, bookmark);
|
||||
}
|
||||
},
|
||||
[mutations.REMOVE_BOOKMARK](state, id) {
|
||||
const index = state.bookmarks.findIndex(bookmark => bookmark.id === id);
|
||||
if (index !== -1) {
|
||||
state.bookmarks.splice(index, 1);
|
||||
Vue.delete(state.bookmarksById, id);
|
||||
}
|
||||
},
|
||||
[mutations.REMOVE_ALL_BOOKMARKS](state) {
|
||||
state.bookmarks = [];
|
||||
state.bookmarksById = {};
|
||||
},
|
||||
|
||||
[mutations.SET_SIDEBAR](state, sidebar) {
|
||||
state.sidebar = sidebar;
|
||||
},
|
||||
|
||||
[mutations.INCREMENT_PAGE](state) {
|
||||
Vue.set(state.fetchState, 'page', state.fetchState.page + 1);
|
||||
},
|
||||
[mutations.SET_QUERY](state, query) {
|
||||
state.bookmarks = [];
|
||||
state.bookmarksById = {};
|
||||
Vue.set(state.fetchState, 'page', 0);
|
||||
Vue.set(state.fetchState, 'reachedEnd', false);
|
||||
Vue.set(state.fetchState, 'query', query);
|
||||
},
|
||||
[mutations.FETCH_START](state, type) {
|
||||
Vue.set(state.loading, type, true);
|
||||
},
|
||||
[mutations.FETCH_END](state, type) {
|
||||
Vue.set(state.loading, type, false);
|
||||
},
|
||||
|
||||
[mutations.REACHED_END](state) {
|
||||
Vue.set(state.fetchState, 'reachedEnd', true);
|
||||
}
|
||||
};
|
|
@ -1,6 +1,4 @@
|
|||
<?php
|
||||
/** @var $l \OCP\IL10N */
|
||||
/** @var $_ array */
|
||||
script('bookmarks', 'bookmarks.admin');
|
||||
?>
|
||||
<div id="bookmarks" class="section"></div>
|
||||
|
|
Loading…
Reference in New Issue