mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 09:47:08 +00:00
Add Vuex projects module.
Not to be confused with the `project` module. `projects`: lists all available projects `project`: lists details for one project
This commit is contained in:
@@ -4,6 +4,7 @@ import Vuex from 'vuex'
|
||||
import api from './modules/api'
|
||||
import user from './modules/user'
|
||||
import snack from './modules/snack'
|
||||
import projects from './modules/projects'
|
||||
import project from './modules/project'
|
||||
import event from './modules/event'
|
||||
import label from './modules/label'
|
||||
@@ -19,6 +20,7 @@ export default new Vuex.Store({
|
||||
api,
|
||||
user,
|
||||
snack,
|
||||
projects,
|
||||
project,
|
||||
event,
|
||||
label,
|
||||
|
||||
120
lib/www/client/source/src/store/modules/projects/actions.js
Normal file
120
lib/www/client/source/src/store/modules/projects/actions.js
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
/** Fetch projects from server
|
||||
*/
|
||||
async function refreshProjects ({commit, dispatch, state, rootState}) {
|
||||
|
||||
if (state.loading) {
|
||||
commit('abortProjectsLoading');
|
||||
}
|
||||
|
||||
commit('setProjectsLoading');
|
||||
const pid = rootState.project.projectId;
|
||||
const url = `/project`;
|
||||
const init = {
|
||||
signal: state.loading.signal
|
||||
};
|
||||
const res = await dispatch('api', [url, init]);
|
||||
|
||||
if (res) {
|
||||
commit('setProjects', res);
|
||||
commit('setProjectsTimestamp');
|
||||
}
|
||||
commit('clearProjectsLoading');
|
||||
}
|
||||
|
||||
/** Return a subset of projects from state.projects
|
||||
*/
|
||||
async function getProjects ({commit, dispatch, state}, [{pid, name, schema, group, sortBy, sortDesc, itemsPerPage, page, text}] = [{}]) {
|
||||
let filteredProjects = [...state.projects];
|
||||
|
||||
if (sortBy) {
|
||||
|
||||
sortBy.forEach( (key, idx) => {
|
||||
filteredProjects.sort( (el0, el1) => {
|
||||
const a = el0?.[key];
|
||||
const b = el1?.[key];
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else if (a == b) {
|
||||
return 0;
|
||||
} else if (a && !b) {
|
||||
return 1;
|
||||
} else if (!a && b) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
if (sortDesc && sortDesc[idx] === true) {
|
||||
filteredProjects.reverse();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
filteredProjects = filteredProjects.filter( project => project.pid == pid );
|
||||
}
|
||||
|
||||
if (name) {
|
||||
filteredProjects = filteredProjects.filter( project => project.name.toLowerCase().includes(name.toLowerCase()) );
|
||||
}
|
||||
|
||||
if (schema) {
|
||||
filteredProjects = filteredProjects.filter( project => project.schema.toLowerCase().includes(schema.toLowerCase()) );
|
||||
}
|
||||
|
||||
if (group) {
|
||||
filteredProjects = filteredProjects.filter( project => project.groups.find(g => g.toLowerCase() == group.toLowerCase()) );
|
||||
}
|
||||
|
||||
if (text) {
|
||||
const tstampFilter = (value, search, item) => {
|
||||
return search?.length >= 5 && textFilter(value, search, item);
|
||||
};
|
||||
|
||||
const numberFilter = (value, search, item) => {
|
||||
return value == search;
|
||||
};
|
||||
|
||||
const textFilter = (value, search, item) => {
|
||||
return String(value).toLowerCase().includes(search.toLowerCase());
|
||||
};
|
||||
|
||||
const arrayFilter = (elementFilter) => {
|
||||
return (value, search, item) => value.some(element => elementFilter(element, search, item));
|
||||
};
|
||||
|
||||
const searchFunctions = {
|
||||
pid: textFilter,
|
||||
name: textFilter,
|
||||
group: arrayFilter(textFilter)
|
||||
};
|
||||
|
||||
filteredProjects = filteredProjects.filter ( project => {
|
||||
for (let key in searchFunctions) {
|
||||
const fn = searchFunctions[key];
|
||||
if (fn(project[key], text, project)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
const count = filteredProjects.length;
|
||||
|
||||
if (itemsPerPage && itemsPerPage > 0) {
|
||||
const offset = (page > 0)
|
||||
? (page-1) * itemsPerPage
|
||||
: 0;
|
||||
|
||||
filteredProjects = filteredProjects.slice(offset, offset+itemsPerPage);
|
||||
}
|
||||
|
||||
return {projects: filteredProjects, count};
|
||||
}
|
||||
|
||||
export default { refreshProjects, getProjects };
|
||||
18
lib/www/client/source/src/store/modules/projects/getters.js
Normal file
18
lib/www/client/source/src/store/modules/projects/getters.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
function projects (state) {
|
||||
return state.projects;
|
||||
}
|
||||
|
||||
function projectGroups (state) {
|
||||
return [...new Set(state.projects.map(i => i.groups).flat())].sort();
|
||||
}
|
||||
|
||||
function projectCount (state) {
|
||||
return state.projects?.length ?? 0;
|
||||
}
|
||||
|
||||
function projectsLoading (state) {
|
||||
return !!state.loading;
|
||||
}
|
||||
|
||||
export default { projects, projectGroups, projectCount, projectsLoading };
|
||||
@@ -0,0 +1,6 @@
|
||||
import state from './state'
|
||||
import getters from './getters'
|
||||
import actions from './actions'
|
||||
import mutations from './mutations'
|
||||
|
||||
export default { state, getters, actions, mutations };
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
function setProjects (state, projects) {
|
||||
// We don't need or want the array to be reactive
|
||||
state.projects = Object.freeze(projects);
|
||||
}
|
||||
|
||||
function setProjectsLoading (state, abortController = new AbortController()) {
|
||||
state.loading = abortController;
|
||||
}
|
||||
|
||||
// This assumes that we know any transactions have finished or we
|
||||
// don't care about aborting.
|
||||
function clearProjectsLoading (state) {
|
||||
state.loading = null;
|
||||
}
|
||||
|
||||
function setProjectsTimestamp (state, timestamp = new Date()) {
|
||||
// NOTE: There is no `modified_on` property in the projects
|
||||
// result or in the database schema, but we should probably add
|
||||
// one.
|
||||
if (timestamp === true) {
|
||||
const tstamp = state.projects
|
||||
.map( event => event.modified_on )
|
||||
.reduce( (acc, cur) => acc > cur ? acc : cur );
|
||||
state.timestamp = tstamp ? new Date(tstamp) : new Date();
|
||||
} else {
|
||||
state.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
function setProjectsETag (state, etag) {
|
||||
state.etag = etag;
|
||||
}
|
||||
|
||||
function abortProjectsLoading (state) {
|
||||
if (state.loading) {
|
||||
state.loading.abort();
|
||||
}
|
||||
state.loading = null;
|
||||
}
|
||||
|
||||
export default {
|
||||
setProjects,
|
||||
setProjectsLoading,
|
||||
clearProjectsLoading,
|
||||
setProjectsTimestamp,
|
||||
setProjectsETag
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
const state = () => ({
|
||||
projects: Object.freeze([]),
|
||||
loading: null,
|
||||
timestamp: null,
|
||||
etag: null,
|
||||
});
|
||||
|
||||
export default state;
|
||||
Reference in New Issue
Block a user