list editing, deleting

This commit is contained in:
Markus Thielen 2023-03-17 18:41:43 +01:00
parent 3bb07e7d47
commit 9a53cfbaa6
Signed by: markus
GPG Key ID: 3D4980D3EC9C8E26
6 changed files with 229 additions and 98 deletions

View File

@ -1,34 +1,20 @@
[resolvers.createTask]
operation_name = "createTask"
[resolvers.getUser]
operation_name = "getUser"
[resolvers.createTask.resolver]
command_type = "SQLInsert"
[resolvers.getUser.resolver]
command_type = "SQLSelect"
[resolvers.createTask.resolver.command]
table = "Task"
[resolvers.getUser.resolver.command]
table = "User"
columns = []
where_clauses = []
modify_values = []
aggregate_result = true
[[resolvers.createTask.resolver.command.modify_values]]
column = "title"
value = "'$title'"
[[resolvers.createTask.resolver.command.modify_values]]
column = "description"
value = "'$description'"
[[resolvers.createTask.resolver.command.modify_values]]
column = "completed"
value = "$completed"
[[resolvers.createTask.resolver.command.modify_values]]
column = "list_id"
value = "'$list.$id'"
[[resolvers.createTask.resolver.command.modify_values]]
column = "user_username"
value = "'$user.$username'"
[[resolvers.getUser.resolver.command.where_clauses]]
table = "User"
column = "username"
condition_str = "= '$username'"
index = ""
[resolvers.updateTask]
operation_name = "updateTask"
@ -63,38 +49,20 @@ column = "id"
condition_str = "= '$id'"
index = ""
[resolvers.getUser]
operation_name = "getUser"
[resolvers.deleteList]
operation_name = "deleteList"
[resolvers.getUser.resolver]
command_type = "SQLSelect"
[resolvers.getUser.resolver.command]
table = "User"
columns = []
modify_values = []
aggregate_result = true
[[resolvers.getUser.resolver.command.where_clauses]]
table = "User"
column = "username"
condition_str = "= '$username'"
index = ""
[resolvers.deleteTask]
operation_name = "deleteTask"
[resolvers.deleteTask.resolver]
[resolvers.deleteList.resolver]
command_type = "SQLDelete"
[resolvers.deleteTask.resolver.command]
table = "Task"
[resolvers.deleteList.resolver.command]
table = "List"
columns = []
modify_values = []
aggregate_result = true
[[resolvers.deleteTask.resolver.command.where_clauses]]
table = "Task"
[[resolvers.deleteList.resolver.command.where_clauses]]
table = "List"
column = "id"
condition_str = "= '$id'"
index = ""
@ -119,6 +87,77 @@ value = "'$username'"
column = "name"
value = "'$name'"
[resolvers.deleteTask]
operation_name = "deleteTask"
[resolvers.deleteTask.resolver]
command_type = "SQLDelete"
[resolvers.deleteTask.resolver.command]
table = "Task"
columns = []
modify_values = []
aggregate_result = true
[[resolvers.deleteTask.resolver.command.where_clauses]]
table = "Task"
column = "id"
condition_str = "= '$id'"
index = ""
[resolvers.createTask]
operation_name = "createTask"
[resolvers.createTask.resolver]
command_type = "SQLInsert"
[resolvers.createTask.resolver.command]
table = "Task"
columns = []
where_clauses = []
aggregate_result = true
[[resolvers.createTask.resolver.command.modify_values]]
column = "title"
value = "'$title'"
[[resolvers.createTask.resolver.command.modify_values]]
column = "description"
value = "'$description'"
[[resolvers.createTask.resolver.command.modify_values]]
column = "completed"
value = "$completed"
[[resolvers.createTask.resolver.command.modify_values]]
column = "list_id"
value = "'$list.$id'"
[[resolvers.createTask.resolver.command.modify_values]]
column = "user_username"
value = "'$user.$username'"
[resolvers.updateList]
operation_name = "updateList"
[resolvers.updateList.resolver]
command_type = "SQLUpdate"
[resolvers.updateList.resolver.command]
table = "List"
columns = []
aggregate_result = true
[[resolvers.updateList.resolver.command.modify_values]]
column = "title"
value = "'$title'"
[[resolvers.updateList.resolver.command.where_clauses]]
table = "List"
column = "id"
condition_str = "= '$id'"
index = ""
[resolvers.createList]
operation_name = "createList"

View File

@ -54,6 +54,13 @@ type Mutation {
user: User! # username needs to be specified as it's non-nullable
): List @bb_resolver(_type: insert, _object: List, _fields: { title: "$title", user: "$user" })
updateList(
id: ID!,
title: String!
): List @bb_resolver(_type: update, _object: List, _filter: { id: { _eq: "$id" } }, _fields: { title: "$title" })
deleteList(id: ID!): List @bb_resolver(_type: delete, _object: List, _filter: { id: { _eq: "$id" } })
createTask(
title: String!,
description: String,

View File

@ -1,8 +1,8 @@
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/Welcome.vue'
import { store } from './store.js'
import {clearSession} from "./store.js";
import {Modal} from "bootstrap";
/**
* Logout the user.
@ -36,11 +36,14 @@ function dismissError() {
<div v-if="store.session.token" class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<RouterLink to="/about" class="nav-link" active-class="active">About</RouterLink>
<RouterLink to="/" class="nav-link" active-class="active">Tasks</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/lists" class="nav-link" active-class="active">Lists</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/about" class="nav-link" active-class="active">About</RouterLink>
</li>
</ul>
<ul class="navbar-nav mb-2 mb-lg-0">
<li class="navbar-text">Hello, {{ store.session.username }}!</li>
@ -60,6 +63,24 @@ function dismissError() {
<button type="button" class="btn-close" @click="dismissError()" aria-label="Close"></button>
</div>
<!-- message modal -->
<div class="modal" tabindex="-1" id="msgbox">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<RouterView />
</main>

View File

@ -12,7 +12,7 @@
</h1>
<div class="toolbar">
<button type="button" @click="addItem()" class="btn btn-primary btn-large">New List</button>
<button type="button" @click="addList()" class="btn btn-primary btn-large">New List</button>
<div class="ms-auto">
<small>{{ gStore.lists.length }} lists found.</small>
</div>
@ -30,7 +30,8 @@
<i class="bi bi-trash"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Delete this list</a></li>
<li><a class="dropdown-item" href="#"
@click="deleteList(list)">Delete this list</a></li>
</ul>
</div>
<span class="item-counter">
@ -42,7 +43,7 @@
<div class="alert alert-info" v-if="gStore.lists.length === 0">
<p>There are no lists, yet.</p>
<button type="button" @click="addItem()" class="btn btn-primary btn-large">Create your first list</button>
<button type="button" @click="addList()" class="btn btn-primary btn-large">Create your first list</button>
</div>
</transition-group>
</div>
@ -53,7 +54,10 @@
<script>
import {gqlQuery} from "../util/net";
import {store} from "../store";
import {showError, store} from "../store";
import {showModal} from "../util/misc";
const NEW_LIST_ID = "new-list-id";
export default {
name: "Lists",
@ -62,19 +66,87 @@ export default {
/**
* Save a list to the database.
* @param list
* @param list - the list object to save.
*/
saveList(list)
{
/* Prepare request; it is different if the list is new */
let gql = "";
if (list.id === NEW_LIST_ID) {
/* create new list */
gql = `mutation {
createList(
title: "${list.title}"
user: {
username: "${store.session.username}"
}
) {
id
}
}`;
} else {
/* save existing list */
gql = `mutation {
updateList(
id: "${list.id}",
title: "${list.title}"
) {
id
}
}`;
}
/* send query */
gqlQuery(
gql
).then(data => {
/* Save the list's id in case it was just created */
list.id = data.List.id;
}).catch(e => {
const errMsg = `Failed to save list: ${e}`;
console.error(errMsg);
showError(errMsg);
});
},
/**
* Delete a list.
* @param list - the list object to delete
*/
deleteList(list) {
if (list.id !== NEW_LIST_ID) {
/* Make sure the list is not in use */
if (store.tasks.findIndex(task => task.list.id === list.id) !== -1) {
showModal("Delete List", "The list cannot be deleted as it is in use.");
return;
}
/* List must be also deleted from the server */
gqlQuery(`mutation {
deleteList(id: "${list.id}") {
id
}
}`);
}
/* delete list from the store. */
const idx = store.lists.findIndex(item => item.id === list.id);
if (idx !== -1) {
store.lists.splice(idx, 1);
}
},
/**
* Add a new list.
*/
addItem()
addList()
{
/* push it to the array of lists in the store; it will be saved
* when the user leaves the title field.
*/
store.lists.push({
title: "Enter list title",
id: NEW_LIST_ID
});
},
/**

View File

@ -12,24 +12,6 @@
ToDo List
</h1>
<!-- message modal -->
<div class="modal" tabindex="-1" id="msgbox">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div id="filter-form" class="toolbar">
<label class="switch">
@ -37,7 +19,7 @@
Show completed
</label>
<button type="button" @click="addItem()" class="ms-auto btn btn-primary btn-large">Add Item</button>
<button type="button" @click="addTask()" class="ms-auto btn btn-primary btn-large">Add Item</button>
<div class="ms-auto">
<div class="d-flex">
@ -69,7 +51,7 @@
<i class="bi bi-trash"></i>
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" @click="deleteTask(task)">Delete this item</a></li>
<li><a class="dropdown-item" href="" @click="deleteTask(task)">Delete this item</a></li>
</ul>
</div>
</div>
@ -81,7 +63,7 @@
</p>
<p v-if="currentList !== 0">You can add items or select another list.</p>
<hr>
<button type="button" class="btn btn-primary btn-sm" @click="addItem()">Create Todo Item</button>
<button type="button" class="btn btn-primary btn-sm" @click="addTask()">Create Todo Item</button>
</div>
</transition-group>
@ -93,7 +75,7 @@
<script>
import {gqlQuery} from "../util/net";
import {showError, store} from "../store";
import { Modal } from 'bootstrap';
import {showModal} from "../util/misc";
const NEW_TASK_ID = "new-task-id";
@ -158,7 +140,7 @@ export default {
gqlQuery(
request
).then(data => {
/* save the task's id */
/* Save the task's id in case it was just created */
task.id = data.Task.id;
}).catch(e => {
const errMsg = `Failed to save task: ${e}`;
@ -190,23 +172,12 @@ export default {
},
/**
* Show a message nox (Bootstrap modal)
* Add a task to the current list.
*/
showModal(title, text) {
const el = document.getElementById('msgbox');
el.querySelector(".modal-title").innerHTML = title;
el.querySelector(".modal-body").innerHTML = text;
const modal = new Modal(el);
modal.show();
},
/**
* Add an item to the current list.
*/
addItem() {
addTask() {
if (!this.currentList) {
this.showModal("No list selected",
'Please select a specific list (not "All") before adding an item.');
showModal("No list selected",
'Please select a specific list (not "All") before adding an item.');
return;
}

21
src/util/misc.js Normal file
View File

@ -0,0 +1,21 @@
/**
* Misc utility functions.
*
* Part of the basebox sample Todo app.
* https://basebox.tech
*/
import {Modal} from "bootstrap";
/**
* Show a message box (Bootstrap modal).
*
* The markup for the modal is defined in App.vue.
*/
export function showModal(title, text) {
const el = document.getElementById('msgbox');
el.querySelector(".modal-title").innerHTML = title;
el.querySelector(".modal-body").innerHTML = text;
const modal = new Modal(el);
modal.show();
}