Added manage structure page
This commit is contained in:
parent
e1154ec33b
commit
37701a0484
17 changed files with 818 additions and 5 deletions
29
public/api/removeProject.php
Normal file
29
public/api/removeProject.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once(__DIR__ . "/services/apiBranch.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/responses.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
|
||||||
|
|
||||||
|
class RemoveProjectBranch extends ApiBranch
|
||||||
|
{
|
||||||
|
function get(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
respondStatus(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
function post(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
$user_id = $params->get("user_id");
|
||||||
|
|
||||||
|
if ($params->exists(["project_id"]) == false) {
|
||||||
|
respondStatus(400, "Missing parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
removeProject($user_id, $params);
|
||||||
|
|
||||||
|
respondStatus(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$branch = new RemoveProjectBranch();
|
||||||
|
$branch->execute();
|
29
public/api/removeRecordTag.php
Normal file
29
public/api/removeRecordTag.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once(__DIR__ . "/services/apiBranch.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/responses.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
|
||||||
|
|
||||||
|
class RemoveRecordTagBranch extends ApiBranch
|
||||||
|
{
|
||||||
|
function get(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
respondStatus(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
function post(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
$user_id = $params->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();
|
|
@ -222,6 +222,46 @@ function updateRecord($user_id, $record)
|
||||||
$db->execute();
|
$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)
|
function removeRecord($user_id, $params)
|
||||||
{
|
{
|
||||||
$record_id = $params->get("record_id");
|
$record_id = $params->get("record_id");
|
||||||
|
@ -233,6 +273,49 @@ function removeRecord($user_id, $params)
|
||||||
$db->execute();
|
$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)
|
function updateTimeRecord($user_id, $params)
|
||||||
{
|
{
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
29
public/api/updateProject.php
Normal file
29
public/api/updateProject.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once(__DIR__ . "/services/apiBranch.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/responses.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
|
||||||
|
|
||||||
|
class UpdateProjectBranch extends ApiBranch
|
||||||
|
{
|
||||||
|
function get(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
respondStatus(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
function post(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
$user_id = $params->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();
|
29
public/api/updateRecordTag.php
Normal file
29
public/api/updateRecordTag.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once(__DIR__ . "/services/apiBranch.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/responses.inc.php");
|
||||||
|
require_once(__DIR__ . "/services/jugglDbApi.inc.php");
|
||||||
|
|
||||||
|
class UpdateRecordTagBranch extends ApiBranch
|
||||||
|
{
|
||||||
|
function get(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
respondStatus(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
function post(ParamCleaner $params)
|
||||||
|
{
|
||||||
|
$user_id = $params->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();
|
72
src/components/base/BaseConfirmButton.vue
Normal file
72
src/components/base/BaseConfirmButton.vue
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<b-button
|
||||||
|
:pressed.sync="triggered"
|
||||||
|
:size="size"
|
||||||
|
class="inline"
|
||||||
|
:variant="variant"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</b-button>
|
||||||
|
|
||||||
|
<div id="confirm-popover" v-if="triggered" class="inline">
|
||||||
|
<div class="inline">{{ msg }}</div>
|
||||||
|
<b-button
|
||||||
|
@click="triggered = false"
|
||||||
|
:size="size"
|
||||||
|
class="inline"
|
||||||
|
variant="outline-secondary"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
<b-button
|
||||||
|
@click="() => confirm()"
|
||||||
|
:size="size"
|
||||||
|
class="inline"
|
||||||
|
variant="outline-danger"
|
||||||
|
>
|
||||||
|
Yes
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "BaseConfirmButton",
|
||||||
|
props: {
|
||||||
|
size: {
|
||||||
|
required: false,
|
||||||
|
type: String
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
required: false,
|
||||||
|
type: String,
|
||||||
|
default: "outline-danger"
|
||||||
|
},
|
||||||
|
msg: {
|
||||||
|
required: false,
|
||||||
|
type: String,
|
||||||
|
default: "Sure?"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
triggered: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
confirm: function() {
|
||||||
|
this.$emit("click");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass" scoped>
|
||||||
|
.inline
|
||||||
|
display: inline-block
|
||||||
|
|
||||||
|
#confirm-popover *
|
||||||
|
margin-left: 1rem
|
||||||
|
</style>
|
111
src/components/forms/FormProjectDetails.vue
Normal file
111
src/components/forms/FormProjectDetails.vue
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
<template>
|
||||||
|
<b-form @submit="submitForm">
|
||||||
|
<b-form-group id="id-group" label-for="id" label="Record ID">
|
||||||
|
<b-form-input id="id" v-model="form.project_id" required trim disabled>
|
||||||
|
</b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-group id="name-group" label-for="name" label="Name">
|
||||||
|
<b-form-input id="name" v-model="form.name" required trim> </b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-group id="startdate-group" label="Start date" label-for="startdate">
|
||||||
|
<b-form-datepicker
|
||||||
|
id="startdate"
|
||||||
|
v-model="form.start_date"
|
||||||
|
required
|
||||||
|
placeholder="Choose a start date"
|
||||||
|
dark
|
||||||
|
>
|
||||||
|
</b-form-datepicker>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-invalid-feedback :state="!failed">
|
||||||
|
Something went wrong.
|
||||||
|
</b-form-invalid-feedback>
|
||||||
|
<b-button variant="primary" type="submit" class="right" :disabled="working">
|
||||||
|
<b-spinner v-if="working" small />
|
||||||
|
Save
|
||||||
|
</b-button>
|
||||||
|
<b-button variant="outline-secondary" @click="() => cancel()" class="left">
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
<BaseConfirmButton
|
||||||
|
class="left"
|
||||||
|
@click="() => deleteProject()"
|
||||||
|
variant="outline-danger"
|
||||||
|
>
|
||||||
|
<b-icon class="icon-btn" icon="trash" />
|
||||||
|
</BaseConfirmButton>
|
||||||
|
</b-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BaseConfirmButton from "@/components/base/BaseConfirmButton";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "FormProjectDetails",
|
||||||
|
components: {
|
||||||
|
BaseConfirmButton
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
project: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
failed: false,
|
||||||
|
working: false,
|
||||||
|
form: {
|
||||||
|
project_id: undefined,
|
||||||
|
start_date: undefined,
|
||||||
|
name: undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Submits the form. Assupmtion: Form is valid, based on required flags.
|
||||||
|
*/
|
||||||
|
submitForm: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.failed = false;
|
||||||
|
this.working = true;
|
||||||
|
|
||||||
|
store
|
||||||
|
.dispatch("updateProject", this.form)
|
||||||
|
.then(() => {
|
||||||
|
this.working = false;
|
||||||
|
this.$emit("submit");
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.failed = true;
|
||||||
|
this.working = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
cancel: function() {
|
||||||
|
this.$emit("cancel");
|
||||||
|
},
|
||||||
|
deleteProject: function() {
|
||||||
|
store.dispatch("removeProject", this.form.project_id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
this.form.project_id = this.project.project_id;
|
||||||
|
this.form.name = this.project.name;
|
||||||
|
this.form.start_date = this.project.start_date;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.left
|
||||||
|
float: left !important
|
||||||
|
margin-right: 1rem
|
||||||
|
|
||||||
|
.right
|
||||||
|
float: right !important
|
||||||
|
margin-left: 1rem
|
||||||
|
</style>
|
|
@ -106,22 +106,26 @@
|
||||||
<b-button variant="outline-secondary" @click="() => cancel()" class="left">
|
<b-button variant="outline-secondary" @click="() => cancel()" class="left">
|
||||||
Cancel
|
Cancel
|
||||||
</b-button>
|
</b-button>
|
||||||
<b-button
|
<BaseConfirmButton
|
||||||
class="left"
|
class="left"
|
||||||
@click="() => deleteRecord()"
|
@click="() => deleteRecord()"
|
||||||
variant="outline-danger"
|
variant="outline-danger"
|
||||||
>
|
>
|
||||||
<b-icon class="icon-btn" icon="trash" />
|
<b-icon class="icon-btn" icon="trash" />
|
||||||
</b-button>
|
</BaseConfirmButton>
|
||||||
</b-form>
|
</b-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { helperService } from "@/services/helper.service.js";
|
import { helperService } from "@/services/helper.service.js";
|
||||||
|
import BaseConfirmButton from "@/components/base/BaseConfirmButton";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "FormRecordDetails",
|
name: "FormRecordDetails",
|
||||||
|
components: {
|
||||||
|
BaseConfirmButton
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
record: {
|
record: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
|
99
src/components/forms/FormTagDetails.vue
Normal file
99
src/components/forms/FormTagDetails.vue
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<b-form @submit="submitForm">
|
||||||
|
<b-form-group id="id-group" label-for="id" label="Record ID">
|
||||||
|
<b-form-input id="id" v-model="form.record_tag_id" required trim disabled>
|
||||||
|
</b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-group id="name-group" label-for="name" label="Name">
|
||||||
|
<b-form-input id="name" v-model="form.name" required trim> </b-form-input>
|
||||||
|
</b-form-group>
|
||||||
|
<b-form-invalid-feedback :state="!failed">
|
||||||
|
Something went wrong.
|
||||||
|
</b-form-invalid-feedback>
|
||||||
|
<b-button variant="primary" type="submit" class="right" :disabled="working">
|
||||||
|
<b-spinner v-if="working" small />
|
||||||
|
Save
|
||||||
|
</b-button>
|
||||||
|
<b-button variant="outline-secondary" @click="() => cancel()" class="left">
|
||||||
|
Cancel
|
||||||
|
</b-button>
|
||||||
|
<BaseConfirmButton
|
||||||
|
class="left"
|
||||||
|
@click="() => deleteTag()"
|
||||||
|
variant="outline-danger"
|
||||||
|
>
|
||||||
|
<b-icon class="icon-btn" icon="trash" />
|
||||||
|
</BaseConfirmButton>
|
||||||
|
</b-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import BaseConfirmButton from "@/components/base/BaseConfirmButton";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "FormTagDetails",
|
||||||
|
components: {
|
||||||
|
BaseConfirmButton
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
tag: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
failed: false,
|
||||||
|
working: false,
|
||||||
|
form: {
|
||||||
|
record_tag_id: undefined,
|
||||||
|
name: undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* Submits the form. Assupmtion: Form is valid, based on required flags.
|
||||||
|
*/
|
||||||
|
submitForm: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.failed = false;
|
||||||
|
this.working = true;
|
||||||
|
|
||||||
|
store
|
||||||
|
.dispatch("updateTag", this.form)
|
||||||
|
.then(() => {
|
||||||
|
this.working = false;
|
||||||
|
this.$emit("submit");
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.failed = true;
|
||||||
|
this.working = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
cancel: function() {
|
||||||
|
this.$emit("cancel");
|
||||||
|
},
|
||||||
|
deleteTag: function() {
|
||||||
|
store.dispatch("removeTag", this.form.record_tag_id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
this.form.record_tag_id = this.tag.record_tag_id;
|
||||||
|
this.form.name = this.tag.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.left
|
||||||
|
float: left !important
|
||||||
|
margin-right: 1rem
|
||||||
|
|
||||||
|
.right
|
||||||
|
float: right !important
|
||||||
|
margin-left: 1rem
|
||||||
|
</style>
|
|
@ -33,6 +33,9 @@
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<FormTagAdd @submit="() => reloadTags()" />
|
<FormTagAdd @submit="() => reloadTags()" />
|
||||||
|
<b-link to="/manage">
|
||||||
|
Manage tags
|
||||||
|
</b-link>
|
||||||
</div>
|
</div>
|
||||||
</b-popover>
|
</b-popover>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Login from "../views/Login.vue";
|
||||||
import NotFound from "../views/NotFound.vue";
|
import NotFound from "../views/NotFound.vue";
|
||||||
import Home from "../views/Home.vue";
|
import Home from "../views/Home.vue";
|
||||||
import History from "../views/History.vue";
|
import History from "../views/History.vue";
|
||||||
|
import Manage from "../views/Manage.vue";
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
|
@ -24,6 +25,12 @@ const routes = [
|
||||||
component: History,
|
component: History,
|
||||||
beforeEnter: requireAuth
|
beforeEnter: requireAuth
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/manage",
|
||||||
|
name: "Manage",
|
||||||
|
component: Manage,
|
||||||
|
beforeEnter: requireAuth
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/home",
|
path: "/home",
|
||||||
name: "Home",
|
name: "Home",
|
||||||
|
|
|
@ -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 = {}) {
|
getRecords(options = {}) {
|
||||||
var payload = {};
|
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() {
|
getRunningRecords() {
|
||||||
return apiService.post("/getRunningRecords.php").then(r => {
|
return apiService.post("/getRunningRecords.php").then(r => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -101,6 +101,16 @@ export const juggl = {
|
||||||
return Object.values(getters.records).filter(
|
return Object.values(getters.records).filter(
|
||||||
record => record.record_id !== id
|
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: {
|
actions: {
|
||||||
|
@ -272,6 +282,36 @@ export const juggl = {
|
||||||
return true;
|
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() {
|
loadSavedLogin() {
|
||||||
var userId = localStorage.getItem("userId");
|
var userId = localStorage.getItem("userId");
|
||||||
var apiKey = localStorage.getItem("apiKey");
|
var apiKey = localStorage.getItem("apiKey");
|
||||||
|
@ -302,6 +342,42 @@ export const juggl = {
|
||||||
commit("setRecords", records);
|
commit("setRecords", records);
|
||||||
return true;
|
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;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,9 +55,12 @@ body
|
||||||
a
|
a
|
||||||
color: $font-link !important
|
color: $font-link !important
|
||||||
|
|
||||||
&:hover
|
&.btn:hover
|
||||||
color: $background-primary !important
|
color: $background-primary !important
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
color: $primary !important
|
||||||
|
|
||||||
.b-dropdown, .dropdown
|
.b-dropdown, .dropdown
|
||||||
border-radius: 0
|
border-radius: 0
|
||||||
background: #0000
|
background: #0000
|
||||||
|
|
|
@ -5,7 +5,14 @@
|
||||||
</div>
|
</div>
|
||||||
<section v-if="!working">
|
<section v-if="!working">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<b-button :download="downloadFilename" :href="'data:text/plain;charset=utf-8,' + encodeURIComponent(fileOutput)" variant="outline-secondary">Download data</b-button>
|
<b-button
|
||||||
|
:download="downloadFilename"
|
||||||
|
:href="
|
||||||
|
'data:text/plain;charset=utf-8,' + encodeURIComponent(fileOutput)
|
||||||
|
"
|
||||||
|
variant="outline-secondary"
|
||||||
|
>Download data</b-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<JugglRecordsList :records="finishedRecords" />
|
<JugglRecordsList :records="finishedRecords" />
|
||||||
</section>
|
</section>
|
||||||
|
@ -34,7 +41,9 @@ export default {
|
||||||
return store.getters.finishedRecords;
|
return store.getters.finishedRecords;
|
||||||
},
|
},
|
||||||
downloadFilename: function() {
|
downloadFilename: function() {
|
||||||
return "juggl_data_" + helperService.dateAsFilenameString(new Date()) + ".json";
|
return (
|
||||||
|
"juggl_data_" + helperService.dateAsFilenameString(new Date()) + ".json"
|
||||||
|
);
|
||||||
},
|
},
|
||||||
fileOutput: function() {
|
fileOutput: function() {
|
||||||
var content = {
|
var content = {
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="add-project-form">
|
<div id="add-project-form">
|
||||||
<FormProjectAdd />
|
<FormProjectAdd />
|
||||||
|
<b-link to="/manage">
|
||||||
|
Manage projects
|
||||||
|
</b-link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section v-if="finishedRecords.length > 0">
|
<section v-if="finishedRecords.length > 0">
|
||||||
|
|
175
src/views/Manage.vue
Normal file
175
src/views/Manage.vue
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
<template>
|
||||||
|
<LayoutNavbarPrivate title="Manage structures">
|
||||||
|
<section id="projects">
|
||||||
|
<h1>Projects</h1>
|
||||||
|
<FormProjectAdd class="bottom-space" />
|
||||||
|
<b-table
|
||||||
|
:items="allProjects"
|
||||||
|
hover
|
||||||
|
:busy="working"
|
||||||
|
:fields="project_fields"
|
||||||
|
sort-by="name"
|
||||||
|
>
|
||||||
|
<template #table-busy>
|
||||||
|
<div class="text-center">
|
||||||
|
<b-spinner></b-spinner>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Custom data -->
|
||||||
|
<template #cell(duration)="data">
|
||||||
|
{{ getDurationTimestamp(data.item.duration) }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #cell(details)="data">
|
||||||
|
<b-button
|
||||||
|
size="sm"
|
||||||
|
@click="data.toggleDetails"
|
||||||
|
variant="outline-secondary"
|
||||||
|
>
|
||||||
|
<b-icon class="icon-btn" icon="gear" />
|
||||||
|
</b-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #row-details="data">
|
||||||
|
<b-card>
|
||||||
|
<FormProjectDetails
|
||||||
|
:project="data.item"
|
||||||
|
@cancel="data.toggleDetails"
|
||||||
|
@submit="data.toggleDetails"
|
||||||
|
/>
|
||||||
|
</b-card>
|
||||||
|
</template>
|
||||||
|
</b-table>
|
||||||
|
</section>
|
||||||
|
<section id="tags">
|
||||||
|
<h1>Tags</h1>
|
||||||
|
<FormTagAdd class="bottom-space" />
|
||||||
|
<b-table
|
||||||
|
:items="allTags"
|
||||||
|
hover
|
||||||
|
:busy="working"
|
||||||
|
:fields="tag_fields"
|
||||||
|
sort-by="name"
|
||||||
|
>
|
||||||
|
<template #table-busy>
|
||||||
|
<div class="text-center">
|
||||||
|
<b-spinner></b-spinner>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Custom data -->
|
||||||
|
<template #cell(details)="data">
|
||||||
|
<b-button
|
||||||
|
size="sm"
|
||||||
|
@click="data.toggleDetails"
|
||||||
|
variant="outline-secondary"
|
||||||
|
>
|
||||||
|
<b-icon class="icon-btn" icon="gear" />
|
||||||
|
</b-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #row-details="data">
|
||||||
|
<b-card>
|
||||||
|
<FormTagDetails
|
||||||
|
:tag="data.item"
|
||||||
|
@cancel="data.toggleDetails"
|
||||||
|
@submit="data.toggleDetails"
|
||||||
|
/>
|
||||||
|
</b-card>
|
||||||
|
</template>
|
||||||
|
</b-table>
|
||||||
|
</section>
|
||||||
|
</LayoutNavbarPrivate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LayoutNavbarPrivate from "@/components/layout/LayoutNavbarPrivate";
|
||||||
|
import FormProjectDetails from "@/components/forms/FormProjectDetails";
|
||||||
|
import FormProjectAdd from "@/components/forms/FormProjectAdd";
|
||||||
|
import FormTagDetails from "@/components/forms/FormTagDetails";
|
||||||
|
import { helperService } from "@/services/helper.service.js";
|
||||||
|
import FormTagAdd from "@/components/forms/FormTagAdd";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
components: {
|
||||||
|
LayoutNavbarPrivate,
|
||||||
|
FormProjectDetails,
|
||||||
|
FormProjectAdd,
|
||||||
|
FormTagDetails,
|
||||||
|
FormTagAdd
|
||||||
|
},
|
||||||
|
data: () => {
|
||||||
|
return {
|
||||||
|
working: true,
|
||||||
|
project_fields: [
|
||||||
|
{
|
||||||
|
key: "name",
|
||||||
|
label: "Name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "start_date",
|
||||||
|
label: "Start date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "duration",
|
||||||
|
label: "Duration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "record_count",
|
||||||
|
label: "Records"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "details",
|
||||||
|
label: "Details"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tag_fields: [
|
||||||
|
{
|
||||||
|
key: "name",
|
||||||
|
label: "Name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "details",
|
||||||
|
label: "Details"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
store.dispatch("loadProjects");
|
||||||
|
store
|
||||||
|
.dispatch("loadTags")
|
||||||
|
.then(() => {
|
||||||
|
this.working = false;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.working = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
allTags: function() {
|
||||||
|
return Object.values(store.getters.tags);
|
||||||
|
},
|
||||||
|
allProjects: function() {
|
||||||
|
return Object.values(store.getters.projects);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getDurationTimestamp: helperService.getDurationTimestamp
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="sass">
|
||||||
|
.center
|
||||||
|
text-align: center
|
||||||
|
|
||||||
|
.bottom-space
|
||||||
|
margin-bottom: 1rem
|
||||||
|
|
||||||
|
section
|
||||||
|
margin-bottom: 4rem
|
||||||
|
</style>
|
Loading…
Reference in a new issue