Show confirm close alert for unsaved changes

This commit is contained in:
Zaid Abdulla committed 2020-10-25 13:37:35 -07:00
1 parent 36798cfb5f
commit c8a6eb4c72
10 files changed
+472 -388

No files matched your search

+107 -92
View File
@@ -147,37 +147,42 @@ function renderTable(confsResponse, searchString): Children {
{ {
title: "Edit config value", title: "Edit config value",
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
base: conf, base: conf,
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object, false) putActionHandler(action, object, false)
.then((errors) => { .then((errors) => {
const ErrorList = errors ? Object.values(errors) : []; const ErrorList = errors ? Object.values(errors) : [];
if (ErrorList.length) { if (ErrorList.length) {
for (const err of ErrorList) for (const err of ErrorList)
notifications.push("error", err); notifications.push("error", err);
} else { } else {
overlay.close(cb); overlay.close(cb);
} }
resolve(); resolve();
}) })
.catch((err) => { .catch((err) => {
notifications.push("error", err.message); notifications.push("error", err.message);
resolve(); resolve();
}); });
}); });
},
}, },
formData },
) formData
); )
}; );
overlay.open(cb); cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
getIcon("edit") getIcon("edit")
@@ -244,38 +249,43 @@ export const component: ClosureComponent = (): Component => {
{ {
title: "Create new config", title: "Create new config",
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object, true) putActionHandler(action, object, true)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
: []; : [];
if (errorList.length) { if (errorList.length) {
for (const err of errorList) for (const err of errorList)
notifications.push("error", err); notifications.push("error", err);
} else { } else {
overlay.close(cb); overlay.close(cb);
} }
resolve(); resolve();
}) })
.catch((err) => { .catch((err) => {
notifications.push("error", err.message); notifications.push("error", err.message);
resolve(); resolve();
}); });
}); });
},
}, },
formData },
) formData
); )
}; );
overlay.open(cb); cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
"New config" "New config"
@@ -307,39 +317,44 @@ export const component: ClosureComponent = (): Component => {
"button", "button",
{ {
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
uiConfigComponent, uiConfigComponent,
Object.assign( Object.assign(
{ {
onUpdate: (errs: string[]) => { onUpdate: (errs: string[]) => {
const errors = errs ? Object.values(errs) : []; const errors = errs ? Object.values(errs) : [];
if (errors.length) { if (errors.length) {
for (const err of errors) for (const err of errors)
notifications.push("error", err); notifications.push("error", err);
} else { } else {
notifications.push( notifications.push(
"success", "success",
`${sub.name.replace( `${sub.name.replace(
/^[a-z]/, /^[a-z]/,
sub.name[0].toUpperCase() sub.name[0].toUpperCase()
)} config updated` )} config updated`
); );
overlay.close(cb);
}
store.fulfill(0, Date.now());
},
onError: (err) => {
notifications.push("error", err.message);
store.fulfill(0, Date.now());
overlay.close(cb); overlay.close(cb);
}, }
store.fulfill(0, Date.now());
}, },
attrs onError: (err) => {
) notifications.push("error", err.message);
); store.fulfill(0, Date.now());
}; overlay.close(cb);
overlay.open(cb); },
},
attrs
)
);
cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
`Edit ${sub.name}` `Edit ${sub.name}`
+36 -31
View File
@@ -221,38 +221,43 @@ export const component: ClosureComponent = (): Component => {
{ {
title: "Create new file", title: "Create new file",
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object) putActionHandler(action, object)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
: []; : [];
if (errorList.length) { if (errorList.length) {
for (const err of errorList) for (const err of errorList)
notifications.push("error", err); notifications.push("error", err);
} else { } else {
overlay.close(cb); overlay.close(cb);
} }
resolve(); resolve();
}) })
.catch((err) => { .catch((err) => {
notifications.push("error", err.message); notifications.push("error", err.message);
resolve(); resolve();
}); });
}); });
},
}, },
formData },
) formData
); )
}; );
overlay.open(cb); cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
"New" "New"
+14 -5
View File
@@ -20,16 +20,24 @@
import m, { Children } from "mithril"; import m, { Children } from "mithril";
type OverlayCallback = () => Children; type OverlayCallback = () => Children;
type CloseCallback = () => boolean;
let overlayCallback: OverlayCallback = null; let overlayCallback: OverlayCallback = null;
let closeCallback: CloseCallback = null;
export function open(callback: OverlayCallback): void { export function open(
callback: OverlayCallback,
closeCb: CloseCallback = null
): void {
overlayCallback = callback; overlayCallback = callback;
closeCallback = closeCb;
} }
export function close(callback: OverlayCallback): boolean { export function close(callback: OverlayCallback, force = true): boolean {
if (callback === overlayCallback) { if (callback === overlayCallback) {
if (!force && closeCallback && !closeCallback()) return false;
overlayCallback = null; overlayCallback = null;
closeCallback = null;
return true; return true;
} }
@@ -43,7 +51,7 @@ export function render(): Children {
{ {
tabindex: 0, tabindex: 0,
onclick: () => { onclick: () => {
close(overlayCallback); close(overlayCallback, false);
}, },
style: "opacity: 0", style: "opacity: 0",
oncreate: (vnode) => { oncreate: (vnode) => {
@@ -75,9 +83,10 @@ export function render(): Children {
} }
document.addEventListener("keydown", (e) => { document.addEventListener("keydown", (e) => {
if (overlayCallback && e.keyCode === 27 && close(overlayCallback)) m.redraw(); if (overlayCallback && e.keyCode === 27 && close(overlayCallback, false))
m.redraw();
}); });
window.addEventListener("popstate", () => { window.addEventListener("popstate", () => {
if (close(overlayCallback)) m.redraw(); if (close(overlayCallback, false)) m.redraw();
}); });
+36 -31
View File
@@ -285,38 +285,43 @@ export const component: ClosureComponent = (): Component => {
{ {
title: "Create new permission", title: "Create new permission",
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object) putActionHandler(action, object)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
: []; : [];
if (errorList.length) { if (errorList.length) {
for (const err of errorList) for (const err of errorList)
notifications.push("error", err); notifications.push("error", err);
} else { } else {
overlay.close(cb); overlay.close(cb);
} }
resolve(); resolve();
}) })
.catch((err) => { .catch((err) => {
notifications.push("error", err.message); notifications.push("error", err.message);
resolve(); resolve();
}); });
}); });
},
}, },
formData },
) formData
); )
}; );
overlay.open(cb); cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
"New" "New"
+64 -53
View File
@@ -287,7 +287,38 @@ export const component: ClosureComponent = (): Component => {
"a", "a",
{ {
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
const comp = m(
putFormComponent,
Object.assign(
{
base: preset,
actionHandler: (action, object) => {
return new Promise((resolve) => {
putActionHandler(action, object, false)
.then((errors) => {
const errorList = errors
? Object.values(errors)
: [];
if (errorList.length) {
for (const err of errorList)
notifications.push("error", err);
} else {
overlay.close(cb);
}
resolve();
})
.catch((err) => {
notifications.push("error", err.message);
resolve();
});
});
},
},
formData
)
);
cb = (): Children => {
if (!preset.provision) { if (!preset.provision) {
return m( return m(
"div", "div",
@@ -295,15 +326,37 @@ export const component: ClosureComponent = (): Component => {
"This UI only supports presets with a single 'provision' configuraiton. If this preset was originally created from the old UI (genieacs-gui), you must edit it there." "This UI only supports presets with a single 'provision' configuraiton. If this preset was originally created from the old UI (genieacs-gui), you must edit it there."
); );
} }
return comp;
};
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
},
},
"Show"
),
];
};
return m( if (window.authorizer.hasAccess("presets", 3)) {
attrs["actionsCallback"] = (selected: Set<string>): Children => {
return [
m(
"button.primary",
{
title: "Create new preset",
onclick: () => {
let cb: () => Children = null;
const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
base: preset,
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object, false) putActionHandler(action, object, true)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
@@ -326,55 +379,13 @@ export const component: ClosureComponent = (): Component => {
formData formData
) )
); );
}; cb = () => comp;
overlay.open(cb); overlay.open(
}, cb,
}, () =>
"Show" !comp.state["current"]["modified"] ||
), confirm("You have unsaved changes. Close anyway?")
]; );
};
if (window.authorizer.hasAccess("presets", 3)) {
attrs["actionsCallback"] = (selected: Set<string>): Children => {
return [
m(
"button.primary",
{
title: "Create new preset",
onclick: () => {
const cb = (): Children => {
return m(
putFormComponent,
Object.assign(
{
actionHandler: (action, object) => {
return new Promise((resolve) => {
putActionHandler(action, object, true)
.then((errors) => {
const errorList = errors
? Object.values(errors)
: [];
if (errorList.length) {
for (const err of errorList)
notifications.push("error", err);
} else {
overlay.close(cb);
}
resolve();
})
.catch((err) => {
notifications.push("error", err.message);
resolve();
});
});
},
},
formData
)
);
};
overlay.open(cb);
}, },
}, },
"New" "New"
+63 -53
View File
@@ -207,15 +207,67 @@ export const component: ClosureComponent = (): Component => {
"a", "a",
{ {
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent,
Object.assign(
{
base: provision,
actionHandler: (action, object) => {
return new Promise((resolve) => {
putActionHandler(action, object, false)
.then((errors) => {
const errorList = errors
? Object.values(errors)
: [];
if (errorList.length) {
for (const err of errorList)
notifications.push("error", err);
} else {
overlay.close(cb);
}
resolve();
})
.catch((err) => {
notifications.push("error", err.message);
resolve();
});
});
},
},
formData
)
);
cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
},
},
"Show"
),
];
};
if (window.authorizer.hasAccess("provisions", 3)) {
attrs["actionsCallback"] = (selected: Set<string>): Children => {
return [
m(
"button.primary",
{
title: "Create new provision",
onclick: () => {
let cb: () => Children = null;
const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
base: provision,
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object, false) putActionHandler(action, object, true)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
@@ -238,55 +290,13 @@ export const component: ClosureComponent = (): Component => {
formData formData
) )
); );
}; cb = () => comp;
overlay.open(cb); overlay.open(
}, cb,
}, () =>
"Show" !comp.state["current"]["modified"] ||
), confirm("You have unsaved changes. Close anyway?")
]; );
};
if (window.authorizer.hasAccess("provisions", 3)) {
attrs["actionsCallback"] = (selected: Set<string>): Children => {
return [
m(
"button.primary",
{
title: "Create new provision",
onclick: () => {
const cb = (): Children => {
return m(
putFormComponent,
Object.assign(
{
actionHandler: (action, object) => {
return new Promise((resolve) => {
putActionHandler(action, object, true)
.then((errors) => {
const errorList = errors
? Object.values(errors)
: [];
if (errorList.length) {
for (const err of errorList)
notifications.push("error", err);
} else {
overlay.close(cb);
}
resolve();
})
.catch((err) => {
notifications.push("error", err.message);
resolve();
});
});
},
},
formData
)
);
};
overlay.open(cb);
}, },
}, },
"New" "New"
+7
View File
@@ -56,6 +56,7 @@ function createField(current, attr, focus): Children {
: null, : null,
onchange: (e) => { onchange: (e) => {
current.object[attr.id] = e.target.value; current.object[attr.id] = e.target.value;
current.modified = true;
e.redraw = false; e.redraw = false;
}, },
}, },
@@ -80,6 +81,7 @@ function createField(current, attr, focus): Children {
if (e.target.checked) currentSelected.add(op); if (e.target.checked) currentSelected.add(op);
else currentSelected.delete(op); else currentSelected.delete(op);
current.object[attr.id] = Array.from(currentSelected); current.object[attr.id] = Array.from(currentSelected);
current.modified = true;
e.redraw = false; e.redraw = false;
}, },
}; };
@@ -98,6 +100,7 @@ function createField(current, attr, focus): Children {
}, },
onChange: (value) => { onChange: (value) => {
current.object[attr.id] = value; current.object[attr.id] = value;
current.modified = true;
}, },
}; };
return m(codeEditorComponent, attrs); return m(codeEditorComponent, attrs);
@@ -112,6 +115,7 @@ function createField(current, attr, focus): Children {
: null, : null,
onchange: (e) => { onchange: (e) => {
current.object[attr.id] = e.target.files; current.object[attr.id] = e.target.files;
current.modified = true;
e.redraw = false; e.redraw = false;
}, },
}); });
@@ -132,6 +136,7 @@ function createField(current, attr, focus): Children {
: null, : null,
oninput: (e) => { oninput: (e) => {
current.object[attr.id] = e.target.value; current.object[attr.id] = e.target.value;
current.modified = true;
e.redraw = false; e.redraw = false;
}, },
onkeypress: (e) => { onkeypress: (e) => {
@@ -158,6 +163,7 @@ function createField(current, attr, focus): Children {
: null, : null,
oninput: (e) => { oninput: (e) => {
current.object[attr.id] = e.target.value; current.object[attr.id] = e.target.value;
current.modified = true;
e.redraw = false; e.redraw = false;
}, },
}); });
@@ -174,6 +180,7 @@ const component: ClosureComponent = (): Component => {
vnode.state["current"] = { vnode.state["current"] = {
isNew: !base["_id"], isNew: !base["_id"],
object: Object.assign({}, base), object: Object.assign({}, base),
modified: false,
}; };
} }
+1
View File
@@ -120,6 +120,7 @@ const component: ClosureComponent = (): Component => {
}, },
onChange: (value) => { onChange: (value) => {
vnode.state["updatedYaml"] = value; vnode.state["updatedYaml"] = value;
vnode.state["modified"] = true;
}, },
}; };
+81 -70
View File
@@ -237,46 +237,46 @@ export const component: ClosureComponent = (): Component => {
"a", "a",
{ {
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
const children = [ const comp = m(
m( putFormComponent,
putFormComponent, Object.assign(
Object.assign( {
{ base: {
base: { _id: user._id,
_id: user._id, roles: user.roles.split(","),
roles: user.roles.split(","), },
}, actionHandler: (action, object) => {
actionHandler: (action, object) => { return new Promise((resolve) => {
return new Promise((resolve) => { putActionHandler(action, object, false)
putActionHandler(action, object, false) .then((errors) => {
.then((errors) => { const errorList = errors
const errorList = errors ? Object.values(errors)
? Object.values(errors) : [];
: []; if (errorList.length) {
if (errorList.length) { for (const err of errorList)
for (const err of errorList) notifications.push("error", err);
notifications.push("error", err); } else {
} else { overlay.close(cb);
overlay.close(cb); }
} resolve();
resolve(); })
}) .catch((err) => {
.catch((err) => { notifications.push("error", err.message);
notifications.push("error", err.message); resolve();
resolve();
});
}); });
}, });
}, },
{ },
resource: "users", {
attributes: attributes, resource: "users",
} attributes: attributes,
) }
), )
]; );
cb = () => {
const children: Children = [comp];
if (canWrite) { if (canWrite) {
children.push(m("hr")); children.push(m("hr"));
const _attrs = { const _attrs = {
@@ -292,7 +292,13 @@ export const component: ClosureComponent = (): Component => {
return children; return children;
}; };
overlay.open(cb);
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
"Show" "Show"
@@ -317,38 +323,43 @@ export const component: ClosureComponent = (): Component => {
{ {
title: "Create new user", title: "Create new user",
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object, true) putActionHandler(action, object, true)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
: []; : [];
if (errorList.length) { if (errorList.length) {
for (const err of errorList) for (const err of errorList)
notifications.push("error", err); notifications.push("error", err);
} else { } else {
overlay.close(cb); overlay.close(cb);
} }
resolve(); resolve();
}) })
.catch((err) => { .catch((err) => {
notifications.push("error", err.message); notifications.push("error", err.message);
resolve(); resolve();
}); });
}); });
},
}, },
formData },
) formData
); )
}; );
overlay.open(cb); cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
}, },
}, },
"New" "New"
+63 -53
View File
@@ -207,15 +207,67 @@ export const component: ClosureComponent = (): Component => {
"a", "a",
{ {
onclick: () => { onclick: () => {
const cb = (): Children => { let cb: () => Children = null;
return m( const comp = m(
putFormComponent,
Object.assign(
{
base: virtualParameter,
actionHandler: (action, object) => {
return new Promise((resolve) => {
putActionHandler(action, object, false)
.then((errors) => {
const errorList = errors
? Object.values(errors)
: [];
if (errorList.length) {
for (const err of errorList)
notifications.push("error", err);
} else {
overlay.close(cb);
}
resolve();
})
.catch((err) => {
notifications.push("error", err.message);
resolve();
});
});
},
},
formData
)
);
cb = () => comp;
overlay.open(
cb,
() =>
!comp.state["current"]["modified"] ||
confirm("You have unsaved changes. Close anyway?")
);
},
},
"Show"
),
];
};
if (window.authorizer.hasAccess("virtualParameters", 3)) {
attrs["actionsCallback"] = (selected: Set<string>): Children => {
return [
m(
"button.primary",
{
title: "Create new virtual parameter",
onclick: () => {
let cb: () => Children = null;
const comp = m(
putFormComponent, putFormComponent,
Object.assign( Object.assign(
{ {
base: virtualParameter,
actionHandler: (action, object) => { actionHandler: (action, object) => {
return new Promise((resolve) => { return new Promise((resolve) => {
putActionHandler(action, object, false) putActionHandler(action, object, true)
.then((errors) => { .then((errors) => {
const errorList = errors const errorList = errors
? Object.values(errors) ? Object.values(errors)
@@ -238,55 +290,13 @@ export const component: ClosureComponent = (): Component => {
formData formData
) )
); );
}; cb = () => comp;
overlay.open(cb); overlay.open(
}, cb,
}, () =>
"Show" !comp.state["current"]["modified"] ||
), confirm("You have unsaved changes. Close anyway?")
]; );
};
if (window.authorizer.hasAccess("virtualParameters", 3)) {
attrs["actionsCallback"] = (selected: Set<string>): Children => {
return [
m(
"button.primary",
{
title: "Create new virtual parameter",
onclick: () => {
const cb = (): Children => {
return m(
putFormComponent,
Object.assign(
{
actionHandler: (action, object) => {
return new Promise((resolve) => {
putActionHandler(action, object, true)
.then((errors) => {
const errorList = errors
? Object.values(errors)
: [];
if (errorList.length) {
for (const err of errorList)
notifications.push("error", err);
} else {
overlay.close(cb);
}
resolve();
})
.catch((err) => {
notifications.push("error", err.message);
resolve();
});
});
},
},
formData
)
);
};
overlay.open(cb);
}, },
}, },
"New" "New"