Add collection and new vocab + mess with repository

This commit is contained in:
2024-11-04 17:16:16 +01:00
parent f8e470b096
commit 0a41ff4a7b
28 changed files with 2599 additions and 38 deletions

View File

@@ -0,0 +1,72 @@
{% extends 'data_entry.html.twig' %}
{% block title %}Bibliography - Add new | ArCOA{% endblock %}
{% block rightpanel %}
<div class="container" style="max-width: 60vw">
<h1 class="is-size-1 mt-0 has-text-centered">Bibliography</h1>
<h2 class="is-size-3 mt-3 has-text-centered">Add new record</h2>
<p class="pt-4 pb-4 has-text-link has-text-weight-bold">Fields marked with (*) are mandatory</p>
<div class="card p-5 has-background-light">
{{ form_start(form) }}
<div class="field">
<label class="label">
{{ form_label(form.status) }}
</label>
<div class="select">
{{ form_widget(form.status) }}
</div>
</div>
<div class="field">
<label class="label">
{{ form_label(form.editor) }}
</label>
<div class="control">
{{
form_widget(
form.editor,
{'attr': {'class': 'input', 'placeholder': 'Name of the editor (mandatory)'}}
)
}}
</div>
</div>
<div class="field">
<label class="label">
{{ form_label(form.citation) }}
</label>
<div class="control">
{{ form_widget(form.citation, {'attr': {'class': 'input'}}) }}
</div>
</div>
<div class="field">
<label class="label">
{{ form_label(form.reference) }}
</label>
<div class="control">
{{ form_widget(form.reference, {'attr': {'class': 'textarea'}}) }}
</div>
</div>
<div class="field">
<label class="label">
{{ form_label(form.notes) }}
</label>
<div class="control">
{{ form_widget(form.notes, {'attr': {'class': 'textarea'}}) }}
</div>
</div>
<div class="field is-grouped is-grouped-right mt-5">
<div class="control">
<button type="submit" class="button is-link">
Save
<span class="icon ml-3">
<i class="fa fa-save"></i>
</span>
</button>
</div>
</div>
{{ form_end(form) }}
</div>
</div>
<script type="text/javascript" defer></script>
{% endblock %}

View File

@@ -1,6 +1,6 @@
{% extends 'data_entry.html.twig' %}
{% block title %}Bibliography | ArCOA{% endblock %}
{% block title %}Bibliography - {{ record.citation }} | ArCOA{% endblock %}
{% block rightpanel %}
<div class="container" style="max-width: 60vw">
@@ -16,6 +16,7 @@
<p><strong>Editor:</strong> {{ record.editor }}</p>
</div>
</article>
<div class="card p-5">
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_REVISOR') %}
<div class="columns">
@@ -27,12 +28,18 @@
<i class="fa fa-edit"></i>
</span>
</button>
<button class="button is-danger ml-2">
<button class="button is-link">
Copy
<span class="icon ml-2">
<i class="fa fa-copy"></i>
</span>
</button>
<a href="{{ path('app_bibliography_del', {'id' : record.id}) }}" class="button is-danger" id="del-record">
Delete
<span class="icon ml-2">
<i class="fa fa-trash"></i>
</span>
</button>
</a>
</div>
</div>
{% endif %}
@@ -55,7 +62,56 @@
<div class="data-tabs is-hidden" id="relations">
Some stuff...
</div>
</div>
</div>
</div>
<script type="text/javascript" defer></script>
<div class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<span class="icon is-large has-text-warning">
<i class="fa fa-warning fa-2x"></i>
</span>
<p class="modal-card-title has-text-danger pl-2"><strong>Delete record?</strong></p>
<button class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<p class="is-size-5">This record will be permanently deleted. Proceed?</p>
</section>
<footer class="modal-card-foot">
<div class="buttons is-right">
<button class="button is-link" id="confirm-del">Confirm</button>
<button class="button is-light" id="cancel">Cancel</button>
</div>
</footer>
</div>
</div>
<script type="text/javascript" defer>
const del = document.querySelector('#del-record');
const delPath = del.href;
del.addEventListener('click', event => {
event.preventDefault();
const modal = document.querySelector('.modal');
modal.classList.add('is-active');
modal.querySelector('.delete').addEventListener('click', () => {
modal.classList.remove('is-active');
});
modal.querySelector('.modal-background').addEventListener('click', () => {
modal.classList.remove('is-active');
});
modal.querySelector('#cancel').addEventListener('click', () => {
modal.classList.remove('is-active');
});
// Proceed with deletion...
modal.querySelector('#confirm-del').addEventListener('click', () => {
location.href = delPath;
});
});
</script>
{% endblock %}

View File

@@ -7,19 +7,25 @@
<h1 class="is-size-1 mt-0 has-text-centered">Bibliography</h1>
<h2 class="is-size-3 mt-3 has-text-centered">Choose action</h2>
{% for message in app.flashes('notice') %}
<div class=" mt-4 notification is-success">
<button class="delete"></button>
{{ message }}
</div>
{% endfor %}
<div class="card p-5 mt-6 pt-6 pb-6">
<div class="columns">
<div class="column is-half has-text-centered">
<a href="{{ path('app_bibliography_search') }}" class="button is-large">
<button class="button is-medium">
Search
<span class="icon ml-2">
<i class="fa fa-search"></i>
</span>
</a>
</button>
</div>
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_REVISOR') or is_granted('ROLE_EDITOR') %}
<div class="column has-text-centered">
<a href="{{ path('app_bibliography_add') }}" class="button is-link is-large">
<a href="{{ path('app_bibliography_create') }}" class="button is-link is-medium">
Add new
<span class="icon ml-2">
<i class="fa fa-plus"></i>
@@ -29,6 +35,54 @@
{% endif %}
</div>
</div>
<h3 class="has-text-centered is-size-4 mt-6">Records</h3>
<p class="pt-4 pb-4"><strong>{{ count }} result(s) found</strong></p>
<table class="table is-hoverable is-fullwidth mt-5 has-text-centered results">
<tr>
<th>ID</th>
<th>Citation</th>
<th>Status</th>
<th>Editor</th>
<th>Reference</th>
<th>Last modified</th>
<th>Actions</th>
</tr>
{% for record in records %}
<tr>
<td><a href="{{ path('app_bibliography', {'id' : record.id}) }}">{{ record.id }}</a></td>
<td><a href="{{ path('app_bibliography', {'id' : record.id}) }}">{{ record.citation }}</a></td>
<td>{{ record.status }}</td>
<td>{{ record.owner }}</td>
<td style="max-width: 350px;">{{ record.reference }}</td>
<td>
{{ record.modifiedAt.format('Y-m-d') }}<br>
{{ record.editor }} at {{ record.modifiedAt.format('H:i:s') }}
</td>
<td style="min-width: 120px;">
<div class="buttons">
<button class="button is-small is-link" title="Edit record">
<span class="icon">
<i class="fa fa-edit"></i>
</span>
</button>
<button class="button is-small is-danger" title="Delete record">
<span class="icon">
<i class="fa fa-trash"></i>
</span>
</button>
</div>
</td>
</tr>
{% endfor %}
</table>
</div>
<script type="text/javascript" defer></script>
<script type="text/javascript" defer>
const delBtns = document.querySelectorAll('.delete');
for (let btn of delBtns) {
btn.addEventListener('click', function () {
this.parentElement.classList.add('is-hidden');
})
}
</script>
{% endblock %}

View File

@@ -0,0 +1,89 @@
{% extends 'data_entry.html.twig' %}
{% block title %}Collection - {{ record.title }} | ArCOA{% endblock %}
{% block rightpanel %}
<div class="container" style="max-width: 60vw">
<h1 class="is-size-1 mt-0 has-text-centered">Collection</h1>
<h2 class="is-size-3 mt-3 has-text-centered">{{ record.title }}</h2>
<article class="message is-info mt-3">
<div class="message-body">
<p>
<strong>Last modified:</strong> {{ record.modifiedAt.format('Y-m-d') }}
at {{ record.modifiedAt.format('H:i:s') }}
</p>
<p><strong>Editor:</strong> {{ record.editor }}</p>
</div>
</article>
<div class="card p-5">
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_REVISOR') %}
<div class="columns">
<div class="column is-half"></div>
<div class="column has-text-right">
<button class="button is-link">
Edit
<span class="icon ml-2">
<i class="fa fa-edit"></i>
</span>
</button>
<button class="button is-link">
Copy
<span class="icon ml-2">
<i class="fa fa-copy"></i>
</span>
</button>
<button class="button is-danger">
Delete
<span class="icon ml-2">
<i class="fa fa-trash"></i>
</span>
</button>
</div>
</div>
{% endif %}
<div class="tabs is-boxed is-fullwidth">
<ul>
<li class="is-active">Record</li>
<li>Relations</li>
</ul>
</div>
<div class="data-tabs" id="record">
<table class="table is-fullwidth pt-4 record">
<tr><th>Record ID</th><td>{{ record.id }}</td></tr>
<tr><th>Status</th><td>{{ record.getStatus() }}</td></tr>
<tr><th>Editor(s)</th><td>{{ record.editor }}</td></tr>
<tr><th>Collection name</th><td>{{ record.title }}</td></tr>
<tr><th>Chronology</th><td>{{ record.chronology }}</td></tr>
<tr><th>Start date</th><td>{{ record.startDate }}</td></tr>
<tr><th>End date</th><td>{{ record.endDate }}</td></tr>
<tr><th>Description</th><td>{{ record.description }}</td></tr>
<tr><th>Short description</th><td>{{ record.shortDescription }}</td></tr>
<tr><th>External identifier(s)</th><td>{{ record.externalIdentifier }}</td></tr>
<tr><th>External link(s)</th><td>{{ record.link }}</td></tr>
<tr><th>Subject headings</th><td>{{ record.subjectHeadings }}</td></tr>
<tr><th>ArCOA URI</th><td>{{ record.uri }}</td></tr>
<tr><th>Editorial notes</th><td>{{ record.notes }}</td></tr>
</table>
</div>
<div class="data-tabs is-hidden" id="relations">
{% if record.bibliographies %}
<p class="p-4 has-text-bold">Bibliographies</p>
<table class="table is-fullwidth is-hoverable has-text-centered">
<tr><th>ID</th><th>Status</th><th>Citation</th><th>Editor</th><th>Reference</th></tr>
{% for biblio in record.bibliographies %}
<tr>
<td><a href="{{ path('app_bibliography', {'id' : biblio.id}) }}">{{ biblio.id }}</a></td>
<td><a href="{{ path('app_bibliography', {'id' : biblio.id}) }}">{{ biblio.citation }}</a></td>
<td>{{ biblio.status }}</td>
<td>{{ biblio.editor }}</td>
<td>{{ biblio.reference }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</div>
</div>
</div>
<script type="text/javascript" defer></script>
{% endblock %}

View File

@@ -3,9 +3,12 @@
{% block body %}
<nav class="navbar has-background-light">
<div class="navbar-start">
<div class="navbar-start ml-4">
<a href="/" class="navbar-item">
<strong>ArCOA Data Entry</strong>
<span class="icon is-clickable">
<i class="fa fa-home"></i>
</span>
<strong>ArCOA Digital Archive</strong>
</a>
</div>
{% if app.user %}
@@ -56,8 +59,8 @@
</nav>
<div class="columns mb-0">
<div class="column is-one-fifth arcoa-menu mb-0">
<aside class="menu pl-4">
{% if 'ROLE_READER' not in app.user.roles %}
<aside class="menu">
{% if 'ROLE_READER' not in app.user.roles %}
<p class="menu-label has-text-white mt-3 pt-5 pl-5 is-size-6">
Vocabularies
<span class="icon is-clickable pl-4" id="for-vocabs">
@@ -146,7 +149,7 @@
</a>
</li>
<li>
<a>
<a href="{{ path('app_vocab_object_type') }}">
<span class="icon pr-3">
<i class="fa fa-plus"></i>
</span>
@@ -209,6 +212,18 @@
<i class="fa fa-angle-right"></i>
</span>
</p>
<ul class="pl-6 is-hidden has-text-white" id="records">
<li>
<a href="{{ path('app_bibliography_landing') }}">
Bibliography
</a>
</li>
<li>
<a href="">
Collection
</a>
</li>
</ul>
</aside>
</div>
<div class="column mt-6 mb-6">

View File

@@ -87,7 +87,7 @@
terms.addEventListener('click', async (event) => {
const clicked = event.target;
if (clicked.classList.contains('is-danger')) {
if (clicked.getAttribute('data-id-delete')) {
const termId = clicked.getAttribute('data-id-delete');
const data = new FormData;
@@ -103,7 +103,7 @@
if (res.status === 200) {
notice.innerHTML = `
<button class="delete"></button>
Term updated successfully
Term deleted successfully
`;
notice.classList.remove('is-hidden');
notice.querySelector('.delete').addEventListener('click', () => {

View File

@@ -0,0 +1,167 @@
{% extends 'data_entry.html.twig' %}
{% block title %}Vocab - Functional context | ArCOA{% endblock %}
{% block rightpanel %}
<div class="container" style="max-width: 50vw">
<h1 class="is-size-1 mt-0 has-text-centered">Vocabulary</h1>
<h2 class="is-size-3 mt-4 has-text-centered">Object type</h2>
<div class="container mt-6">
<!-- For AJAX calls... TODO: not working from controller? -->
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_REVISOR') %}
<form method="post" action="{{ path('app_vocab_func_context_add') }}">
<label class="label">Add new term</label>
<div class="field has-addons">
<div class="control">
<input class="input" name="_term" type="text" placeholder="Add new term">
</div>
<div class="control">
<button type="submit" class="button is-link">
Add
<span class="icon ml-3">
<i class="fa fa-plus"></i>
</span>
</button>
</div>
</div>
</form>
{% endif %}
<div class="notification is-success is-hidden mt-5" id="ajax-success">
</div>
{% for message in app.flashes('notice') %}
<div class="notification is-success mt-5" id="server-success">
<button class="delete"></button>
{{ message }}
</div>
{% endfor %}
<h3 class="mt-6 mb-5 is-size-5"><strong>Terms in vocabulary</strong></h3>
<table class="table is-fullwidth" id="terms">
<tr><th>Term</th>{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_REVISOR') %}<th>Actions</th>{% endif %}</tr>
{% for term in terms %}
<tr data-row-id="{{ term.id }}">
<td>
<input class="input" type="text" value="{{ term.term }}" disabled data-term-id="{{ term.id }}" />
</td>
{% if is_granted('ROLE_ADMIN') or is_granted('ROLE_REVISOR') %}
<td>
<div class="buttons">
<button class="button is-primary is-hidden" data-id-save="{{ term.id }}">
Save
<span class="icon ml-2">
<i class="fa fa-save"></i>
</span>
</button>
<button class="button is-link" data-id-edit="{{ term.id }}">
Edit
<span class="icon ml-2">
<i class="fa fa-edit"></i>
</span>
</button>
<button class="button is-danger" data-id-delete="{{ term.id }}">
Delete
<span class="icon ml-2">
<i class="fa fa-trash"></i>
</span>
</button>
</div>
</td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
</div>
<script type="text/javascript" defer>
const terms = document.querySelector('#terms');
const serverNotice = document.querySelector('#server-success');
if (serverNotice) {
serverNotice.querySelector('.delete').addEventListener('click', () => {
serverNotice.remove();
});
}
terms.addEventListener('click', async (event) => {
const clicked = event.target;
if (clicked.getAttribute('data-id-delete')) {
const termId = clicked.getAttribute('data-id-delete');
const data = new FormData;
data.append("_id", termId);
const res = await fetch("{{ path('app_vocab_func_context_del') }}", {
method: "POST",
body: data,
});
const notice = document.querySelector('#ajax-success');
if (res.status === 200) {
notice.innerHTML = `
<button class="delete"></button>
Term deleted successfully
`;
notice.classList.remove('is-hidden');
notice.querySelector('.delete').addEventListener('click', () => {
notice.classList.add('is-hidden');
});
const row = document.querySelector(`tr[data-row-id="${termId}"]`);
row.remove();
}
}
if (clicked.getAttribute('data-id-edit')) {
const termId = clicked.getAttribute('data-id-edit');
const saveBtn = document.querySelector(`button[data-id-save="${termId}"]`);
const input = document.querySelector(`input[data-term-id="${termId}"]`);
input.disabled = input.disabled ? false : true;
saveBtn.classList.toggle('is-hidden');
clicked.classList.toggle('is-link');
if (!clicked.classList.contains('is-link')) {
clicked.innerHTML = `
Cancel
<span class="icon ml-2">
<i class="fa fa-times"></i>
</span>
`;
} else {
clicked.innerHTML = `
Edit
<span class="icon ml-2">
<i class="fa fa-edit"></i>
</span>
`;
}
const data = new FormData;
data.append("_id", termId);
saveBtn.addEventListener('click', async () => {
data.append("_new_term", input.value);
const res = await fetch("{{ path('app_vocab_func_context_upd') }}", {
method: "POST",
body: data,
});
const notice = document.querySelector('#ajax-success');
if (res.status === 200) {
notice.innerHTML = `
<button class="delete"></button>
Term updated successfully
`;
notice.classList.remove('is-hidden');
notice.querySelector('.delete').addEventListener('click', () => {
notice.classList.add('is-hidden');
});
}
});
}
});
</script>
{% endblock %}