add autosave

This commit is contained in:
bkmartinjr
2021-01-22 14:07:34 -08:00
parent 023976c992
commit e0a0b77c5b
4 changed files with 134 additions and 18 deletions
+79
View File
@@ -387,3 +387,82 @@ export const saveObsAnnotationsAction = () => async (dispatch, getState) => {
});
}
};
export const saveGenesetsAction = () => async (dispatch, getState) => {
const state = getState();
const { config, genesets, annotations } = state;
// bail if gene sets not available, or in readonly mode.
const genesetsAreAvailable =
config?.parameters?.["annotations_genesets"] ?? false;
const genesetsReadonly =
config?.parameters?.["annotations_genesets_readonly"] ?? true;
if (!genesetsAreAvailable || genesetsReadonly) {
// our non-save was completed!
dispatch({
type: "autosave: genesets complete",
lastSavedGenesets: genesets,
});
}
/*
JSON data structure is an array of arrays, where the first
element is gene set name, remainder are the genes. Eg,
{
"genesets": [
[ "gs1", ["TNFRSF4","SUMO3","BRWD1"]],
[ "gs2", ["DSCR3", "BRWD1", "BACE2", "SIK1", "C21orf33", "ICOSLG", "SUMO3"]]
]
}
Order of gene sets and genes is significant
*/
const gsArr = [];
for (const [gsName, gsGenes] of genesets.genesets) {
gsArr.push([gsName, Array.from(gsGenes)]);
}
try {
const { dataCollectionNameIsReadOnly, dataCollectionName } = annotations;
const queryString =
!dataCollectionNameIsReadOnly && !!dataCollectionName
? `?annotation-collection-name=${encodeURIComponent(
dataCollectionName
)}`
: "";
const res = await fetch(
`${globals.API.prefix}${globals.API.version}genesets${queryString}`,
{
method: "PUT",
headers: new Headers({
Accept: "application/json",
"Content-Type": "application/json",
}),
body: JSON.stringify({
genesets: gsArr,
}),
credentials: "include",
}
);
if (res.ok) {
dispatch({
type: "autosave: genesets complete",
lastSavedGenesets: genesets,
});
} else {
dispatch({
type: "autosave: genesets error",
message: `HTTP error ${res.status} - ${res.statusText}`,
res,
});
}
} catch (error) {
dispatch({
type: "autosave: genesets error",
message: error.toString(),
error,
});
}
};
+15 -6
View File
@@ -52,14 +52,21 @@ async function userInfoFetch(dispatch) {
});
}
async function genesetsFetch(dispatch) {
return fetchJson("genesets").then((response) => {
const genesets = response?.genesets ?? {};
async function genesetsFetch(dispatch, config) {
if (config?.parameters?.["annotations_genesets"] ?? false) {
fetchJson("genesets").then((response) => {
const genesets = response?.genesets ?? {};
dispatch({
type: "geneset: initial load",
init: genesets,
});
});
} else {
dispatch({
type: "geneset: initial load",
init: genesets,
init: [],
});
})
}
}
function prefetchEmbeddings(annoMatrix) {
@@ -84,9 +91,10 @@ const doInitialDataLoad = () =>
schemaFetch(dispatch),
userColorsFetchAndLoad(dispatch),
userInfoFetch(dispatch),
genesetsFetch(dispatch),
]);
genesetsFetch(dispatch, config);
const baseDataUrl = `${globals.API.prefix}${globals.API.version}`;
const annoMatrix = new AnnoMatrixLoader(baseDataUrl, schema.schema);
const obsCrossfilter = new AnnoMatrixObsCrossfilter(annoMatrix);
@@ -253,6 +261,7 @@ export default {
annotationRenameLabelInCategory: annoActions.annotationRenameLabelInCategory,
annotationLabelCurrentSelection: annoActions.annotationLabelCurrentSelection,
saveObsAnnotationsAction: annoActions.saveObsAnnotationsAction,
saveGenesetsAction: annoActions.saveGenesetsAction,
needToSaveObsAnnotations: annoActions.needToSaveObsAnnotations,
layoutChoiceAction: embActions.layoutChoiceAction,
setCellSetFromSelection: selnActions.setCellSetFromSelection,
@@ -17,6 +17,9 @@ import {
auth: state.config?.authentication,
userInfo: state.userInfo,
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
writableGenesetsEnabled: !(
state.config?.parameters?.["annotations_genesets_readonly"] ?? true
),
}))
class FilenameDialog extends React.Component {
constructor(props) {
@@ -101,7 +104,7 @@ class FilenameDialog extends React.Component {
} = this.props;
const { filenameText } = this.state;
return writableCategoriesEnabled &&
return (writableCategoriesEnabled || writableGenesetsEnabled) &&
annotations.promptForFilename &&
!annotations.dataCollectionNameIsReadOnly &&
!annotations.dataCollectionName &&
+36 -11
View File
@@ -5,11 +5,18 @@ import FilenameDialog from "./filenameDialog";
@connect((state) => ({
annotations: state.annotations,
saveInProgress: state.autosave?.saveInProgress ?? false,
obsAnnotationSaveInProgress:
state.autosave?.obsAnnotationSaveInProgress ?? false,
genesetSaveInProgress: state.autosave?.genesetSaveInProgress ?? false,
error: state.autosave?.error,
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
writableGenesetsEnabled: !(
state.config?.parameters?.annotations_genesets_readonly ?? true
),
annoMatrix: state.annoMatrix,
genesets: state.genesets,
lastSavedAnnoMatrix: state.autosave?.lastSavedAnnoMatrix,
lastSavedGenesets: state.autosave?.lastSavedGenesets,
}))
class Autosave extends React.Component {
constructor(props) {
@@ -38,18 +45,40 @@ class Autosave extends React.Component {
}
tick = () => {
const { dispatch, saveInProgress } = this.props;
if (this.needToSave() && !saveInProgress) {
const {
dispatch,
obsAnnotationSaveInProgress,
genesetSaveInProgress,
} = this.props;
if (!obsAnnotationSaveInProgress && this.needToSaveObsAnnotations()) {
dispatch(actions.saveObsAnnotationsAction());
}
if (!genesetSaveInProgress && this.needToSaveGenesets()) {
dispatch(actions.saveGenesetsAction());
}
};
needToSave = () => {
/* return true if we need to save, false if we don't */
saveInProgress() {
const { obsAnnotationSaveInProgress, genesetSaveInProgress } = this.props;
return obsAnnotationSaveInProgress || genesetSaveInProgress;
}
needToSaveObsAnnotations = () => {
/* return true if we need to save obs cell labels, false if we don't */
const { annoMatrix, lastSavedAnnoMatrix } = this.props;
return actions.needToSaveObsAnnotations(annoMatrix, lastSavedAnnoMatrix);
};
needToSaveGenesets = () => {
/* return true if we need to save gene ses, false if we do not */
const { genesets, lastSavedGenesets } = this.props;
return genesets.initialized && genesets !== lastSavedGenesets;
};
needToSave() {
return this.needToSaveGenesets() || this.needToSaveObsAnnotations();
}
statusMessage() {
const { error } = this.props;
if (error) {
@@ -59,11 +88,7 @@ class Autosave extends React.Component {
}
render() {
const {
writableCategoriesEnabled,
saveInProgress,
lastSavedAnnoMatrix,
} = this.props;
const { writableCategoriesEnabled, lastSavedAnnoMatrix } = this.props;
const initialDataLoadComplete = lastSavedAnnoMatrix;
if (!writableCategoriesEnabled) return null;
@@ -74,7 +99,7 @@ class Autosave extends React.Component {
data-testclass={
!initialDataLoadComplete
? "autosave-init"
: this.needToSave() || saveInProgress
: this.saveInProgress() || this.needToSave()
? "autosave-incomplete"
: "autosave-complete"
}