diff --git a/public/api/removeProject.php b/public/api/removeProject.php
new file mode 100644
index 0000000..2f1f9c8
--- /dev/null
+++ b/public/api/removeProject.php
@@ -0,0 +1,29 @@
+get("user_id");
+
+ if ($params->exists(["project_id"]) == false) {
+ respondStatus(400, "Missing parameter");
+ }
+
+ removeProject($user_id, $params);
+
+ respondStatus(200);
+ }
+}
+
+$branch = new RemoveProjectBranch();
+$branch->execute();
diff --git a/public/api/removeRecordTag.php b/public/api/removeRecordTag.php
new file mode 100644
index 0000000..2923f3c
--- /dev/null
+++ b/public/api/removeRecordTag.php
@@ -0,0 +1,29 @@
+get("user_id");
+
+ if ($params->exists(["record_tag_id"]) == false) {
+ respondStatus(400, "Missing parameter");
+ }
+
+ removeRecordTag($user_id, $params);
+
+ respondStatus(200);
+ }
+}
+
+$branch = new RemoveRecordTagBranch();
+$branch->execute();
diff --git a/public/api/services/jugglDbApi.inc.php b/public/api/services/jugglDbApi.inc.php
index 00064fe..df8ffea 100644
--- a/public/api/services/jugglDbApi.inc.php
+++ b/public/api/services/jugglDbApi.inc.php
@@ -222,6 +222,46 @@ function updateRecord($user_id, $record)
$db->execute();
}
+function updateProject($user_id, $project)
+{
+ $project_id = $project["project_id"];
+
+ // Update given parameters
+ $data = [];
+ $props = ["name", "start_date"];
+ foreach ($props as $p) {
+ if (array_key_exists ($p, $project)) {
+ $data[$p] = $project[$p];
+ }
+ }
+
+ $db = new DbOperations();
+ $db->update("projects", $data);
+ $db->where("user_id", Comparison::EQUAL, $user_id);
+ $db->where("project_id", Comparison::EQUAL, $project_id);
+ $db->execute();
+}
+
+function updateRecordTag($user_id, $tag)
+{
+ $record_tag_id = $tag["record_tag_id"];
+
+ // Update given parameters
+ $data = [];
+ $props = ["name"];
+ foreach ($props as $p) {
+ if (array_key_exists ($p, $tag)) {
+ $data[$p] = $tag[$p];
+ }
+ }
+
+ $db = new DbOperations();
+ $db->update("record_tags", $data);
+ $db->where("user_id", Comparison::EQUAL, $user_id);
+ $db->where("record_tag_id", Comparison::EQUAL, $record_tag_id);
+ $db->execute();
+}
+
function removeRecord($user_id, $params)
{
$record_id = $params->get("record_id");
@@ -233,6 +273,49 @@ function removeRecord($user_id, $params)
$db->execute();
}
+function removeProject($user_id, $params)
+{
+ $project_id = $params->get("project_id");
+
+ $db = new DbOperations();
+ $db->delete("projects");
+ $db->where("user_id", Comparison::EQUAL, $user_id);
+ $db->where("project_id", Comparison::EQUAL, $project_id);
+ $db->execute();
+
+ removeRecordsOfProject($user_id, $project_id);
+}
+
+function removeRecordsOfProject($user_id, $project_id)
+{
+ $db = new DbOperations();
+ $db->delete("time_records");
+ $db->where("user_id", Comparison::EQUAL, $user_id);
+ $db->where("project_id", Comparison::EQUAL, $project_id);
+ $db->execute();
+}
+
+function removeRecordTag($user_id, $params)
+{
+ $record_tag_id = $params->get("record_tag_id");
+
+ $db = new DbOperations();
+ $db->delete("record_tags");
+ $db->where("user_id", Comparison::EQUAL, $user_id);
+ $db->where("record_tag_id", Comparison::EQUAL, $record_tag_id);
+ $db->execute();
+
+ removeRecordTagFromAssociations($record_tag_id);
+}
+
+function removeRecordTagFromAssociations($record_tag_id)
+{
+ $db = new DbOperations();
+ $db->delete("tags_on_records");
+ $db->where("record_tag_id", Comparison::EQUAL, $record_tag_id);
+ $db->execute();
+}
+
function updateTimeRecord($user_id, $params)
{
$data = [];
diff --git a/public/api/updateProject.php b/public/api/updateProject.php
new file mode 100644
index 0000000..21fc0c0
--- /dev/null
+++ b/public/api/updateProject.php
@@ -0,0 +1,29 @@
+get("user_id");
+
+ if ($params->exists(["project"]) == false) {
+ respondStatus(400, "Missing parameter");
+ }
+
+ updateProject($user_id, $params->get("project"));
+
+ respondStatus(200);
+ }
+}
+
+$branch = new UpdateProjectBranch();
+$branch->execute();
diff --git a/public/api/updateRecordTag.php b/public/api/updateRecordTag.php
new file mode 100644
index 0000000..2606ec5
--- /dev/null
+++ b/public/api/updateRecordTag.php
@@ -0,0 +1,29 @@
+get("user_id");
+
+ if ($params->exists(["record_tag"]) == false) {
+ respondStatus(400, "Missing parameter");
+ }
+
+ updateRecordTag($user_id, $params->get("record_tag"));
+
+ respondStatus(200);
+ }
+}
+
+$branch = new UpdateRecordTagBranch();
+$branch->execute();
diff --git a/src/components/base/BaseConfirmButton.vue b/src/components/base/BaseConfirmButton.vue
new file mode 100644
index 0000000..e5f07bb
--- /dev/null
+++ b/src/components/base/BaseConfirmButton.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
{{ msg }}
+
+ Cancel
+
+
confirm()"
+ :size="size"
+ class="inline"
+ variant="outline-danger"
+ >
+ Yes
+
+
+
+
+
+
+
+
diff --git a/src/components/forms/FormProjectDetails.vue b/src/components/forms/FormProjectDetails.vue
new file mode 100644
index 0000000..09c047c
--- /dev/null
+++ b/src/components/forms/FormProjectDetails.vue
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Something went wrong.
+
+
+
+ Save
+
+ cancel()" class="left">
+ Cancel
+
+ deleteProject()"
+ variant="outline-danger"
+ >
+
+
+
+
+
+
+
+
diff --git a/src/components/forms/FormRecordDetails.vue b/src/components/forms/FormRecordDetails.vue
index 1869a1d..ba25448 100644
--- a/src/components/forms/FormRecordDetails.vue
+++ b/src/components/forms/FormRecordDetails.vue
@@ -106,22 +106,26 @@
cancel()" class="left">
Cancel
- deleteRecord()"
variant="outline-danger"
>
-
+
+
+
diff --git a/src/components/juggl/JugglTagField.vue b/src/components/juggl/JugglTagField.vue
index 56bd862..903cd83 100644
--- a/src/components/juggl/JugglTagField.vue
+++ b/src/components/juggl/JugglTagField.vue
@@ -33,6 +33,9 @@
reloadTags()" />
+
+ Manage tags
+
diff --git a/src/router/index.js b/src/router/index.js
index 7ad8dd3..69587e8 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -5,6 +5,7 @@ import Login from "../views/Login.vue";
import NotFound from "../views/NotFound.vue";
import Home from "../views/Home.vue";
import History from "../views/History.vue";
+import Manage from "../views/Manage.vue";
Vue.use(VueRouter);
@@ -24,6 +25,12 @@ const routes = [
component: History,
beforeEnter: requireAuth
},
+ {
+ path: "/manage",
+ name: "Manage",
+ component: Manage,
+ beforeEnter: requireAuth
+ },
{
path: "/home",
name: "Home",
diff --git a/src/services/juggl.service.js b/src/services/juggl.service.js
index a111243..ff9c11c 100644
--- a/src/services/juggl.service.js
+++ b/src/services/juggl.service.js
@@ -63,6 +63,32 @@ export const jugglService = {
});
},
+ removeProject(projectId) {
+ return apiService
+ .post("/removeProject.php", {
+ project_id: projectId
+ })
+ .then(r => {
+ return {
+ data: r.data,
+ msg: ""
+ };
+ });
+ },
+
+ removeRecordTag(tagId) {
+ return apiService
+ .post("/removeRecordTag.php", {
+ record_tag_id: tagId
+ })
+ .then(r => {
+ return {
+ data: r.data,
+ msg: ""
+ };
+ });
+ },
+
getRecords(options = {}) {
var payload = {};
@@ -94,6 +120,32 @@ export const jugglService = {
});
},
+ updateProject(project) {
+ var payload = {
+ project: project
+ };
+
+ return apiService.post("/updateProject.php", payload).then(r => {
+ return {
+ data: r.data,
+ msg: ""
+ };
+ });
+ },
+
+ updateRecordTag(tag) {
+ var payload = {
+ record_tag: tag
+ };
+
+ return apiService.post("/updateRecordTag.php", payload).then(r => {
+ return {
+ data: r.data,
+ msg: ""
+ };
+ });
+ },
+
getRunningRecords() {
return apiService.post("/getRunningRecords.php").then(r => {
return {
diff --git a/src/store/modules/juggl.js b/src/store/modules/juggl.js
index 1cfa4e6..a20d84a 100644
--- a/src/store/modules/juggl.js
+++ b/src/store/modules/juggl.js
@@ -101,6 +101,16 @@ export const juggl = {
return Object.values(getters.records).filter(
record => record.record_id !== id
);
+ },
+ getProjectsExceptId: (state, getters) => id => {
+ return Object.values(getters.projects).filter(
+ project => project.project_id !== id
+ );
+ },
+ getTagsExceptId: (state, getters) => id => {
+ return Object.values(getters.tags).filter(
+ tag => tag.record_tag_id !== id
+ );
}
},
actions: {
@@ -272,6 +282,36 @@ export const juggl = {
return true;
});
},
+ removeProject({ commit, getters }, projectId) {
+ if (projectId === undefined) {
+ return false;
+ }
+
+ return jugglService
+ .removeProject(projectId)
+ .catch(() => {
+ return false;
+ })
+ .then(() => {
+ commit("setProjects", getters.getProjectsExceptId(projectId));
+ return true;
+ });
+ },
+ removeTag({ commit, getters }, tagId) {
+ if (tagId === undefined) {
+ return false;
+ }
+
+ return jugglService
+ .removeRecordTag(tagId)
+ .catch(() => {
+ return false;
+ })
+ .then(() => {
+ commit("setTags", getters.getTagsExceptId(tagId));
+ return true;
+ });
+ },
loadSavedLogin() {
var userId = localStorage.getItem("userId");
var apiKey = localStorage.getItem("apiKey");
@@ -302,6 +342,42 @@ export const juggl = {
commit("setRecords", records);
return true;
});
+ },
+ updateTag({ commit, getters }, tag) {
+ if (tag.record_tag_id === undefined) {
+ return;
+ }
+
+ return jugglService
+ .updateRecordTag(tag)
+ .catch(() => {
+ return false;
+ })
+ .then(() => {
+ // TODO: Return updated tag from API
+ var tags = getters.getTagsExceptId(tag.record_tag_id);
+ tags.push(tag);
+ commit("setTags", tags);
+ return true;
+ });
+ },
+ updateProject({ commit, getters }, project) {
+ if (project.project_id === undefined) {
+ return;
+ }
+
+ return jugglService
+ .updateProject(project)
+ .catch(() => {
+ return false;
+ })
+ .then(() => {
+ // TODO: Return updated project from API
+ var projects = getters.getProjectsExceptId(project.project_id);
+ projects.push(project);
+ commit("setProjects", projects);
+ return true;
+ });
}
}
};
diff --git a/src/style/theme.sass b/src/style/theme.sass
index 6d42c18..b4797e2 100644
--- a/src/style/theme.sass
+++ b/src/style/theme.sass
@@ -55,8 +55,11 @@ body
a
color: $font-link !important
- &:hover
+ &.btn:hover
color: $background-primary !important
+
+ &:hover
+ color: $primary !important
.b-dropdown, .dropdown
border-radius: 0
diff --git a/src/views/History.vue b/src/views/History.vue
index 4e5b2a1..996afec 100644
--- a/src/views/History.vue
+++ b/src/views/History.vue
@@ -5,7 +5,14 @@
- Download data
+ Download data
@@ -34,7 +41,9 @@ export default {
return store.getters.finishedRecords;
},
downloadFilename: function() {
- return "juggl_data_" + helperService.dateAsFilenameString(new Date()) + ".json";
+ return (
+ "juggl_data_" + helperService.dateAsFilenameString(new Date()) + ".json"
+ );
},
fileOutput: function() {
var content = {
diff --git a/src/views/Home.vue b/src/views/Home.vue
index 6ef7539..d0bf0eb 100644
--- a/src/views/Home.vue
+++ b/src/views/Home.vue
@@ -11,6 +11,9 @@
+
+ Manage projects
+
diff --git a/src/views/Manage.vue b/src/views/Manage.vue
new file mode 100644
index 0000000..6cc524c
--- /dev/null
+++ b/src/views/Manage.vue
@@ -0,0 +1,175 @@
+
+
+
+ Projects
+
+
+
+
+
+
+
+
+
+
+ {{ getDurationTimestamp(data.item.duration) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+