|
@@ -23,7 +23,7 @@ const app = Vue.createApp({
|
|
|
name: "",
|
|
|
lineage: "",
|
|
|
summary: "",
|
|
|
- config: {},
|
|
|
+ config: {},
|
|
|
creator: {
|
|
|
name: "",
|
|
|
url: "",
|
|
@@ -36,12 +36,16 @@ const app = Vue.createApp({
|
|
|
loading: false,
|
|
|
publishing: false,
|
|
|
edit: false,
|
|
|
+ isOwner: false,
|
|
|
+ isAdmin: false,
|
|
|
view: (global.rule) ? true : false,
|
|
|
preview: (global.rule) ? true : false,
|
|
|
template: (global.rule) ? true : false,
|
|
|
steinAPI: 'https://api.steinhq.com/v1/storages/5e8b937ab88d3d04ae0816a5',
|
|
|
- backendUrl: 'http://localhost:3000/api/validate_otp',
|
|
|
+ backendUrl: 'http://localhost:3000/api/publish_rule',
|
|
|
backendUrlrule: 'http://localhost:3000/api/get_rule',
|
|
|
+ backedDeleterule: 'http://localhost:3000/api/delete_rule',
|
|
|
+ adminMail: "communityrule@medlab.host",
|
|
|
// TODO keep an array of past states for undo/redo
|
|
|
history: [],
|
|
|
// the data of the current module in the editor
|
|
@@ -109,7 +113,7 @@ const app = Vue.createApp({
|
|
|
name: "",
|
|
|
icon: "",
|
|
|
summary: "",
|
|
|
- config: {},
|
|
|
+ config: {},
|
|
|
type: "",
|
|
|
modules: []
|
|
|
},
|
|
@@ -193,7 +197,7 @@ const app = Vue.createApp({
|
|
|
name: module.name,
|
|
|
icon: (module.icon && !module.icon.includes('http')) ? global.url + module.icon : module.icon,
|
|
|
summary: module.summary,
|
|
|
- config: module.config,
|
|
|
+ config: module.config,
|
|
|
type: module.type,
|
|
|
modules: (module.modules) ? module.modules.map(cleanModules) : [],
|
|
|
}
|
|
@@ -251,28 +255,28 @@ const app = Vue.createApp({
|
|
|
/**
|
|
|
* @returns {Object} a new module object from the moduleTemplate
|
|
|
*/
|
|
|
- newModule() {
|
|
|
- return JSON.parse(JSON.stringify(this.moduleTemplate));
|
|
|
- },
|
|
|
+ newModule() {
|
|
|
+ return JSON.parse(JSON.stringify(this.moduleTemplate));
|
|
|
+ },
|
|
|
/**
|
|
|
* spreads a source module into a new module from the moduleTemplate
|
|
|
* @param {Object} sourceModule the module to copy
|
|
|
* @param {Boolean} includeSubmodules whether to copy submodules or not
|
|
|
* @returns
|
|
|
*/
|
|
|
- cloneModule(sourceModule,includeSubmodules) {
|
|
|
+ cloneModule(sourceModule, includeSubmodules) {
|
|
|
let output = {
|
|
|
- ...this.moduleTemplate,
|
|
|
- ...sourceModule,
|
|
|
+ ...this.moduleTemplate,
|
|
|
+ ...sourceModule,
|
|
|
//TODO: implement lineage pattern, same as the rule does
|
|
|
source: sourceModule, // keep track of where this module came from
|
|
|
};
|
|
|
if (!includeSubmodules) output.modules = [];
|
|
|
// clear configs
|
|
|
document.getElementById("newConfigKey").value =
|
|
|
- "Configuration";
|
|
|
+ "Configuration";
|
|
|
document.getElementById("newConfigValue").value =
|
|
|
- "Value";
|
|
|
+ "Value";
|
|
|
// delete unnecessary properties
|
|
|
delete output.content;
|
|
|
delete output.readonly;
|
|
@@ -319,7 +323,7 @@ const app = Vue.createApp({
|
|
|
* @param {Object} module to add
|
|
|
* @param {Object} target a module or the rule Object where the module should be added as a submodule
|
|
|
*/
|
|
|
- addModule(module,target = this.rule) {
|
|
|
+ addModule(module, target = this.rule) {
|
|
|
target.modules.push(module);
|
|
|
},
|
|
|
/**
|
|
@@ -330,7 +334,7 @@ const app = Vue.createApp({
|
|
|
* @param {Object} target the module or rule to remove the module from (defaults to rule)
|
|
|
*/
|
|
|
removeModule(module, target = this.rule) {
|
|
|
- if (! this.moduleContains(module, target)) return; // if the module is not in the target, do nothing
|
|
|
+ if (!this.moduleContains(module, target)) return; // if the module is not in the target, do nothing
|
|
|
//
|
|
|
target.modules.forEach((m, idx) => {
|
|
|
if (m === module) {
|
|
@@ -360,8 +364,8 @@ const app = Vue.createApp({
|
|
|
const module = targetModule.module;
|
|
|
|
|
|
ev.dataTransfer.setDragImage(targetModule, ev.offsetX, ev.offsetY);
|
|
|
-
|
|
|
- this.holding = {module};
|
|
|
+
|
|
|
+ this.holding = { module };
|
|
|
},
|
|
|
/**
|
|
|
* Handles the start drag event for a module
|
|
@@ -395,7 +399,7 @@ const app = Vue.createApp({
|
|
|
*/
|
|
|
// TODO: return the module location in the haystack (Maybe?)
|
|
|
moduleContains(needle, haystack = this.rule) {
|
|
|
- if (! haystack.modules ) return false; // does the haystack even have modules?
|
|
|
+ if (!haystack.modules) return false; // does the haystack even have modules?
|
|
|
if (haystack.modules.includes(needle)) return true; // is the needle in the haystack?
|
|
|
return haystack.modules.some(submodule => this.moduleContains(needle, submodule)); // is the needle in any of the submodules?
|
|
|
},
|
|
@@ -425,7 +429,7 @@ const app = Vue.createApp({
|
|
|
// if the module has a source, remove it from that source
|
|
|
this.removeModule(holdingModule, this.holding.source);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
this.addModule(module, landingModule);
|
|
|
this.editModule(module);
|
|
|
this.endDragModule();
|
|
@@ -456,31 +460,31 @@ const app = Vue.createApp({
|
|
|
const store = new SteinStore(
|
|
|
this.steinAPI
|
|
|
);
|
|
|
- const backendUrlGetRule = this.backendUrlrule + "?ruleId="+id;
|
|
|
+ const backendUrlGetRule = this.backendUrlrule + "?ruleId=" + id;
|
|
|
|
|
|
(async () => {
|
|
|
var rule = [];
|
|
|
// read values from all sheets
|
|
|
- console.log(backendUrlGetRule)
|
|
|
+
|
|
|
await fetch(backendUrlGetRule, {
|
|
|
- method: 'GET',
|
|
|
- headers: {
|
|
|
+ method: 'GET',
|
|
|
+ headers: {
|
|
|
'Content-Type': 'application/json',
|
|
|
// Add any other headers you may need, such as authorization headers
|
|
|
- },
|
|
|
- }).then(response => {
|
|
|
- if (!response.ok) {
|
|
|
- throw new Error('Network response was not ok');
|
|
|
- }
|
|
|
- return response.json(); // This returns another Promise
|
|
|
- })
|
|
|
- .then (data => {
|
|
|
+ },
|
|
|
+ }).then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error('Network response was not ok');
|
|
|
+ }
|
|
|
+ return response.json(); // This returns another Promise
|
|
|
+ })
|
|
|
+ .then(data => {
|
|
|
|
|
|
- if (data.rules.length > 0) {
|
|
|
- rule = JSON.parse(data.rules)[0];
|
|
|
- }
|
|
|
+ if (data.rules.length > 0) {
|
|
|
+ rule = JSON.parse(data.rules)[0];
|
|
|
+ }
|
|
|
|
|
|
- });
|
|
|
+ });
|
|
|
// no rule found, exit
|
|
|
// TODO: inform the user that the rule was not found
|
|
|
if (!rule) {
|
|
@@ -506,7 +510,7 @@ const app = Vue.createApp({
|
|
|
name: rule.name,
|
|
|
lineage: rule.lineage,
|
|
|
summary: rule.summary,
|
|
|
- config: rule.config,
|
|
|
+ config: rule.config,
|
|
|
creator: {
|
|
|
name: rule.creator_name,
|
|
|
url: rule.creator_url,
|
|
@@ -515,12 +519,18 @@ const app = Vue.createApp({
|
|
|
latest_version: rule.latest_version
|
|
|
}
|
|
|
|
|
|
- console.log(this.rule.latest_version)
|
|
|
+ if (rule.email == localStorage.getItem('userEmail')) {
|
|
|
+ this.isOwner = true;
|
|
|
+ }
|
|
|
+ if (localStorage.getItem('userEmail') == this.adminMail) {
|
|
|
+ this.isAdmin = true;
|
|
|
+ }
|
|
|
+
|
|
|
/** Add name to <title> for v3+ rules */
|
|
|
document.title = rule.name + " / CommunityRule"
|
|
|
-
|
|
|
+
|
|
|
this.loading = false;
|
|
|
-
|
|
|
+
|
|
|
})();
|
|
|
/*fetch(backendUrlGetRule, {
|
|
|
method: 'GET',
|
|
@@ -584,6 +594,35 @@ const app = Vue.createApp({
|
|
|
},
|
|
|
|
|
|
// editor methods =========================================================
|
|
|
+ clickDelete() {
|
|
|
+ (async () => {
|
|
|
+ // read values from all sheets
|
|
|
+ console.log("rule to delete " + this.rule.ruleID);
|
|
|
+ const requestData = {
|
|
|
+ ruleID: this.rule.ruleID
|
|
|
+ }
|
|
|
+ await fetch(this.backedDeleterule, {
|
|
|
+ method: 'DELETE',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ // Add any other headers you may need, such as authorization headers
|
|
|
+ },
|
|
|
+ body: JSON.stringify(requestData),
|
|
|
+ }).then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error('Network response was not ok');
|
|
|
+ }
|
|
|
+ alert("Error while deleting rule");
|
|
|
+ return response.json(); // This returns another Promise
|
|
|
+ }).then(data => {
|
|
|
+ alert('Rule deleted successfully');
|
|
|
+ window.open("/library", false);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.loading = false;
|
|
|
+
|
|
|
+ })();
|
|
|
+ },
|
|
|
|
|
|
/**
|
|
|
* Adds a module to the editor
|
|
@@ -666,23 +705,23 @@ const app = Vue.createApp({
|
|
|
|
|
|
// config methods =========================================================
|
|
|
|
|
|
- /**
|
|
|
- * Add custom config entry to the module
|
|
|
- */
|
|
|
- addConfig() {
|
|
|
- const k = document.getElementById("newConfigKey").value;
|
|
|
- const v = document.getElementById("newConfigValue").value;
|
|
|
- this.editor.module.config[k] = v;
|
|
|
- this.resetNewConfigInputs();
|
|
|
- },
|
|
|
-
|
|
|
- /**
|
|
|
- * Removes the config entry from the module
|
|
|
- */
|
|
|
- removeConfig(key) {
|
|
|
- delete this.editor.module.config[key];
|
|
|
- },
|
|
|
-
|
|
|
+ /**
|
|
|
+ * Add custom config entry to the module
|
|
|
+ */
|
|
|
+ addConfig() {
|
|
|
+ const k = document.getElementById("newConfigKey").value;
|
|
|
+ const v = document.getElementById("newConfigValue").value;
|
|
|
+ this.editor.module.config[k] = v;
|
|
|
+ this.resetNewConfigInputs();
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Removes the config entry from the module
|
|
|
+ */
|
|
|
+ removeConfig(key) {
|
|
|
+ delete this.editor.module.config[key];
|
|
|
+ },
|
|
|
+
|
|
|
// custom module methods ==================================================
|
|
|
|
|
|
/**
|
|
@@ -733,14 +772,18 @@ const app = Vue.createApp({
|
|
|
*/
|
|
|
handleClickPublish() {
|
|
|
// Confirm user knows what they're getting into
|
|
|
+ if (!localStorage.getItem('userEmail')) {
|
|
|
+ alert('Please login first to publish this rule')
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (!confirm("Publish to the public Library?")) return;
|
|
|
|
|
|
- if ( !this.rule.name ) {
|
|
|
+ if (!this.rule.name) {
|
|
|
alert("Please enter a name for this rule.");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if ( this.rule.modules.length < 1 ) {
|
|
|
+ if (this.rule.modules.length < 1) {
|
|
|
alert("Please add at least one module to this rule.");
|
|
|
return;
|
|
|
}
|
|
@@ -750,78 +793,76 @@ const app = Vue.createApp({
|
|
|
const rule = this.ruleExport;
|
|
|
var ruleID = new Date().getTime(); // TODO: allow for custom named IDs, check for uniqueness
|
|
|
if (this.edit) {
|
|
|
- console.log('asdfasdfasdfasdf' + this.rule.ruleID)
|
|
|
+
|
|
|
ruleID = this.rule.ruleID;
|
|
|
- }
|
|
|
+ }
|
|
|
var latest_ver = 1;
|
|
|
|
|
|
if (this.edit) {
|
|
|
latest_ver = parseInt(this.rule.latest_version) + 1;
|
|
|
- console.log('Updated version' + latest_ver)
|
|
|
}
|
|
|
-// ------------------ exisituing code ---------------
|
|
|
+ // ------------------ exisituing code ---------------
|
|
|
// add to database
|
|
|
- // const store = new SteinStore(
|
|
|
- // this.steinAPI
|
|
|
- // );
|
|
|
-
|
|
|
- // store.append('rules', [{
|
|
|
- // ruleID: ruleID,
|
|
|
- // timestamp: rule.timestamp,
|
|
|
- // icon: rule.icon,
|
|
|
- // name: rule.name,
|
|
|
- // lineage: rule.lineage,
|
|
|
- // summary: rule.summary,
|
|
|
- // config: this.jsonify(rule.config),
|
|
|
- // modules: this.jsonify(rule.modules),
|
|
|
- // creatorName: rule.creator.name,
|
|
|
- // creatorUrl: rule.creator.url,
|
|
|
- // version: 3
|
|
|
- // }]).then(data => {
|
|
|
- // this.publishing = false;
|
|
|
- // window.open("/create/?r=" + ruleID, "_self", false);
|
|
|
- // });
|
|
|
-
|
|
|
- // -=---------------------------- updated code -------------------
|
|
|
-
|
|
|
- const requestData = {
|
|
|
- ruleID: ruleID,
|
|
|
- timestamp: rule.timestamp,
|
|
|
- icon: rule.icon,
|
|
|
- name: rule.name,
|
|
|
- lineage: rule.lineage,
|
|
|
- summary: rule.summary,
|
|
|
- config: this.jsonify(rule.config),
|
|
|
- modules: this.jsonify(rule.modules),
|
|
|
- creatorName: rule.creator.name,
|
|
|
- creatorUrl: rule.creator.url,
|
|
|
- email: 'rota3015@colorado.edu',
|
|
|
- edit: this.edit,
|
|
|
- otp: 1234,
|
|
|
- version: 3,
|
|
|
- latest_version: latest_ver
|
|
|
- }
|
|
|
-
|
|
|
- fetch(this.backendUrl, {
|
|
|
- method: 'POST',
|
|
|
- headers: {
|
|
|
- 'Content-Type': 'application/json',
|
|
|
- 'Access-Control-Allow-Methods': 'POST',
|
|
|
- 'Access-Control-Allow-Headers': 'Content-Type'
|
|
|
- // Add any other headers you may need, such as authorization headers
|
|
|
- },
|
|
|
- body: JSON.stringify(requestData),
|
|
|
+ // const store = new SteinStore(
|
|
|
+ // this.steinAPI
|
|
|
+ // );
|
|
|
+
|
|
|
+ // store.append('rules', [{
|
|
|
+ // ruleID: ruleID,
|
|
|
+ // timestamp: rule.timestamp,
|
|
|
+ // icon: rule.icon,
|
|
|
+ // name: rule.name,
|
|
|
+ // lineage: rule.lineage,
|
|
|
+ // summary: rule.summary,
|
|
|
+ // config: this.jsonify(rule.config),
|
|
|
+ // modules: this.jsonify(rule.modules),
|
|
|
+ // creatorName: rule.creator.name,
|
|
|
+ // creatorUrl: rule.creator.url,
|
|
|
+ // version: 3
|
|
|
+ // }]).then(data => {
|
|
|
+ // this.publishing = false;
|
|
|
+ // window.open("/create/?r=" + ruleID, "_self", false);
|
|
|
+ // });
|
|
|
+
|
|
|
+ // -=---------------------------- updated code -------------------
|
|
|
+
|
|
|
+ const requestData = {
|
|
|
+ ruleID: ruleID,
|
|
|
+ timestamp: rule.timestamp,
|
|
|
+ icon: rule.icon,
|
|
|
+ name: rule.name,
|
|
|
+ lineage: rule.lineage,
|
|
|
+ summary: rule.summary,
|
|
|
+ config: this.jsonify(rule.config),
|
|
|
+ modules: this.jsonify(rule.modules),
|
|
|
+ creatorName: rule.creator.name,
|
|
|
+ creatorUrl: rule.creator.url,
|
|
|
+ email: localStorage.getItem('userEmail'),
|
|
|
+ edit: this.edit,
|
|
|
+ version: 3,
|
|
|
+ latest_version: latest_ver
|
|
|
+ }
|
|
|
+
|
|
|
+ fetch(this.backendUrl, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ 'Access-Control-Allow-Methods': 'POST',
|
|
|
+ 'Access-Control-Allow-Headers': 'Content-Type'
|
|
|
+ // Add any other headers you may need, such as authorization headers
|
|
|
+ },
|
|
|
+ body: JSON.stringify(requestData),
|
|
|
}).then(response => {
|
|
|
if (!response.ok) {
|
|
|
- throw new Error(`HTTP error! Status: ${response.status}`);
|
|
|
+ throw new Error(`HTTP error! Status: ${response.status}`);
|
|
|
}
|
|
|
return response.json(); // or response.text() if expecting plain text
|
|
|
}).then(data => {
|
|
|
// Handle the data received from the backend
|
|
|
console.log('Data from backend:', data);
|
|
|
}).then(data => {
|
|
|
- this.publishing = false;
|
|
|
- window.open("/create/?r=" + ruleID, "_self", false);
|
|
|
+ this.publishing = false;
|
|
|
+ window.open("/create/?r=" + ruleID, "_self", false);
|
|
|
}).catch(error => {
|
|
|
// Handle errors that occurred during the fetch
|
|
|
console.error('Fetch error:', error);
|
|
@@ -889,7 +930,7 @@ const app = Vue.createApp({
|
|
|
* Handles the click event for activating the rule preview
|
|
|
*/
|
|
|
clickPreview() {
|
|
|
- if(this.template) this.rule.icon = ''; // TODO: find a less hacky way to reset template icons
|
|
|
+ if (this.template) this.rule.icon = ''; // TODO: find a less hacky way to reset template icons
|
|
|
this.view = false;
|
|
|
this.preview = !this.preview;
|
|
|
},
|
|
@@ -897,10 +938,10 @@ const app = Vue.createApp({
|
|
|
* Handles the click event for activating the rule preview for edit rule
|
|
|
*/
|
|
|
clickPreviewEdit() {
|
|
|
- if(this.template) this.rule.icon = ''; // TODO: find a less hacky way to reset template icons
|
|
|
- this.view = false;
|
|
|
- this.preview = !this.preview;
|
|
|
- this.edit = true;
|
|
|
+ if (this.template) this.rule.icon = ''; // TODO: find a less hacky way to reset template icons
|
|
|
+ this.view = false;
|
|
|
+ this.preview = !this.preview;
|
|
|
+ this.edit = true;
|
|
|
},
|
|
|
/**
|
|
|
* Filters module library based on the search term
|