Compare commits

..

No commits in common. "73b33f9fb579c41d51045048ce3ac2649092a8dc" and "aeebddd1918525e9bad3e2a3dd7ec4bcde006145" have entirely different histories.

10 changed files with 22 additions and 144 deletions

11
ui/package-lock.json generated
View File

@ -8,7 +8,6 @@
"name": "atsebayt",
"version": "0.0.1",
"dependencies": {
"dayjs": "^1.11.5",
"svelte-frappe-charts": "^1.9.1",
"vite": "^3.0.4"
},
@ -646,11 +645,6 @@
"node": ">= 8"
}
},
"node_modules/dayjs": {
"version": "1.11.5",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz",
"integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA=="
},
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -3097,11 +3091,6 @@
"which": "^2.0.1"
}
},
"dayjs": {
"version": "1.11.5",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz",
"integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA=="
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",

View File

@ -28,7 +28,6 @@
},
"type": "module",
"dependencies": {
"dayjs": "^1.11.5",
"svelte-frappe-charts": "^1.9.1",
"vite": "^3.0.4"
}

View File

@ -1,21 +0,0 @@
<script>
import dayjs from 'dayjs';
export let format = 'YYYY-MM-DD HH:mm';
export let date = new Date();
let className = '';
export { className as class };
export let id = null;
let internal;
const input = (x) => (internal = dayjs(x).format(format));
const output = (x) => (date = dayjs(x, format).toDate().toISOString());
$: input(date)
$: output(internal)
</script>
<input type="datetime-local" class={className} id={id} bind:value={internal}>

View File

@ -1,6 +1,4 @@
<script>
import { createEventDispatcher } from 'svelte';
import DateFormat from '../components/DateFormat.svelte';
import { getUserRendu } from '../lib/works';
@ -9,32 +7,12 @@
export let work = null;
export let user = null;
const dispatch = createEventDispatcher();
let renduP = null;
let submissionP = null;
if (work.submission_url != '-') {
if (work.submission_url) {
renduP = getUserRendu(work.submission_url, user);
renduP.then((rendu) => {
if (rendu !== null) {
dispatch('done');
}
})
} else {
submissionP = work.getSubmission(user.id);
submissionP.then((submission) => {
dispatch('done');
})
}
}
</script>
{#if work.submission_url == '-'}
<!-- Display nothing -->
{:else if work.submission_url}
{#await renduP}
{#await getUserRendu(work.submission_url, user)}
<div class="spinner-border spinner-border-sm" role="status"></div>
{:then rendu}
{#if rendu === null}
@ -46,7 +24,7 @@
<i class="bi text-warning bi-exclamation-triangle-fill" title={error}></i>
{/await}
{:else}
{#await submissionP}
{#await work.getSubmission(user.id)}
<div class="spinner-border spinner-border-sm" role="status"></div>
{:then submission}
<i class="bi text-success bi-check-circle-fill" title={"Rendu effectué : " + JSON.stringify(submission)}></i>

View File

@ -3,7 +3,6 @@
import { goto } from '$app/navigation';
import { getQuestions } from '../lib/questions';
import DateTimeInput from './DateTimeInput.svelte';
import { ToastsStore } from '../stores/toasts';
const dispatch = createEventDispatcher();
@ -14,21 +13,17 @@
dispatch('saved', response);
}, (error) => {
ToastsStore.addErrorToast({
msg: error,
msg: error.errmsg,
});
})
}
let deleteInProgress = false;
function deleteSurvey() {
deleteInProgress = true;
survey.delete().then((response) => {
deleteInProgress = false;
goto(`surveys`);
}, (error) => {
deleteInProgress = false;
ToastsStore.addErrorToast({
msg: error,
msg: error.errmsg,
});
})
}
@ -38,7 +33,7 @@
goto(`surveys/${response.id}`);
}).catch((error) => {
ToastsStore.addErrorToast({
msg: error,
msg: error.errmsg,
});
})
}
@ -109,7 +104,7 @@
<label for="start_availability" class="col-form-label col-form-label-sm">Date de début</label>
</div>
<div class="col-sm-8">
<DateTimeInput class="form-control form-control-sm" id="start_availability" bind:date={survey.start_availability} />
<input type="text" class="form-control form-control-sm" id="start_availability" bind:value={survey.start_availability}>
</div>
</div>
@ -118,7 +113,7 @@
<label for="end_availability" class="col-form-label col-form-label-sm">Date de fin</label>
</div>
<div class="col-8">
<DateTimeInput class="form-control form-control-sm" id="end_availability" bind:date={survey.end_availability} />
<input type="text" class="form-control form-control-sm" id="end_availability" bind:value={survey.end_availability}>
</div>
</div>
@ -142,12 +137,7 @@
<div class="col-sm-10">
<button type="submit" class="btn btn-primary">Enregistrer</button>
{#if survey.id}
<button type="button" class="btn btn-danger" on:click={deleteSurvey} disabled={deleteInProgress}>
{#if deleteInProgress}
<div class="spinner-border spinner-border-sm text-light me-1" role="status"></div>
{/if}
Supprimer
</button>
<button type="button" class="btn btn-danger" on:click={deleteSurvey}>Supprimer</button>
<button type="button" class="btn btn-secondary" on:click={duplicateSurvey}>Dupliquer avec ces nouveaux paramètres</button>
{/if}
</div>

View File

@ -2,7 +2,6 @@
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import DateTimeInput from './DateTimeInput.svelte';
import { ToastsStore } from '../stores/toasts';
const dispatch = createEventDispatcher();
@ -13,7 +12,7 @@
dispatch('saved', response);
}, (error) => {
ToastsStore.addErrorToast({
msg: error,
msg: error.errmsg,
});
})
}
@ -23,7 +22,7 @@
goto(`works`);
}, (error) => {
ToastsStore.addErrorToast({
msg: error,
msg: error.errmsg,
});
})
}
@ -33,7 +32,7 @@
goto(`works/${response.id}`);
}).catch((error) => {
ToastsStore.addErrorToast({
msg: error,
msg: error.errmsg,
});
})
}
@ -103,7 +102,7 @@
<label for="start_availability" class="col-form-label col-form-label-sm">Date de début</label>
</div>
<div class="col-sm-8">
<DateTimeInput class="form-control form-control-sm" id="start_availability" bind:date={work.start_availability} />
<input type="text" class="form-control form-control-sm" id="start_availability" bind:value={work.start_availability}>
</div>
</div>
@ -112,7 +111,7 @@
<label for="end_availability" class="col-form-label col-form-label-sm">Date de fin</label>
</div>
<div class="col-8">
<DateTimeInput class="form-control form-control-sm" id="end_availability" bind:date={work.end_availability} />
<input type="text" class="form-control form-control-sm" id="end_availability" bind:value={work.end_availability}>
</div>
</div>

View File

@ -120,12 +120,6 @@ export class Question {
async delete() {
if (this.id) {
// Start by deleting proposals
const proposals = await this.getProposals();
for (const p of proposals) {
await p.delete();
}
const res = await fetch(`api/questions/${this.id}`, {
method: 'DELETE',
headers: {'Accept': 'application/json'},

View File

@ -1,4 +1,3 @@
import { getCorrectionTemplates } from './correctionTemplates';
import { getQuestions } from './questions';
import { Response } from './response';
import { Work } from './works';
@ -102,33 +101,9 @@ export class Survey {
// Now recopy questions
const questions = await getQuestions(oldSurveyId);
for (const q of questions) {
const oldQuestionId = q.id;
delete q.id;
q.id_survey = response.id;
q.save().then((question) => {
q.id = oldQuestionId;
// Now recopy proposals
if (q.kind == "mcq" || q.kind == "ucq") {
q.getProposals().then((proposals) => {
for (const p of proposals) {
delete p.id;
p.id_question = question.id;
p.save();
}
});
}
// Now recopy correction templates
getCorrectionTemplates(oldQuestionId).then((cts) => {
for (const ct of cts) {
delete ct.id;
ct.id_question = question.id;
ct.save();
}
});
});
q.save();
}
return response;
@ -140,12 +115,6 @@ export class Survey {
async delete() {
if (this.id) {
// Start by deleting questions
const questions = await getQuestions(this.id);
for (const q of questions) {
await q.delete();
}
const res = await fetch(`api/surveys/${this.id}`, {
method: 'DELETE',
headers: {'Accept': 'application/json'},

View File

@ -13,26 +13,20 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { user } from '../../../../stores/user';
import StartStopLiveSurvey from '../../../../components/StartStopLiveSurvey.svelte';
import SurveyAdmin from '../../../../components/SurveyAdmin.svelte';
import SurveyBadge from '../../../../components/SurveyBadge.svelte';
import SurveyQuestions from '../../../../components/SurveyQuestions.svelte';
import { getQuestions } from '../../../../lib/questions';
export let surveyP;
let edit = false;
</script>
{#await surveyP then survey}
{#if $user && $user.is_admin}
<button class="btn btn-primary ms-1 float-end" on:click={() => { edit = !edit; } } title="Éditer"><i class="bi bi-pencil"></i></button>
<StartStopLiveSurvey
{survey}
class="ms-1 float-end"
on:update={() => goto(`surveys/${survey.id}/admin`)}
/>
{/if}
<StartStopLiveSurvey
{survey}
class="ms-1 float-end"
on:update={() => goto(`surveys/${survey.id}/admin`)}
/>
<div class="d-flex align-items-center">
<h2>
<a href="surveys/{survey.id}" class="text-muted" style="text-decoration: none">&lt;</a>
@ -42,10 +36,6 @@
<SurveyBadge class="ms-2" {survey} />
</div>
{#if $user && $user.is_admin && edit}
<SurveyAdmin {survey} on:saved={() => edit = false} />
{/if}
{#await getQuestions(survey.id)}
<div class="text-center">
<div class="spinner-border text-primary mx-3" role="status"></div>

View File

@ -22,14 +22,6 @@
import { getUsers } from '../../../lib/users';
export let work = null;
let usersP = null;
work.then((w) => {
usersP = getUsers(w.promo, w.group);
usersP.then((users) => { nb_users = users.length; });
});
let nb_rendus = 0;
let nb_users = 0;
</script>
{#await work then w}
@ -37,12 +29,12 @@
<h2>
<a href="works/{w.id}" class="text-muted" style="text-decoration: none">&lt;</a>
{w.title}
<small class="text-muted">Rendus {Math.trunc(nb_rendus/nb_users*100)}&nbsp;% ({nb_rendus}/{nb_users})</small>
</h2>
<SurveyBadge class="ms-2" survey={w} />
</div>
{#await usersP then users}
{#await getUsers(w.promo, w.group)}
{:then users}
<table class="w-100 mb-5">
<thead>
<tr>
@ -56,7 +48,7 @@
<tr>
<td><a href="users/{user.login}">{user.login}</a></td>
<td>
<SubmissionStatus work={w} user={user} on:done={() => { nb_rendus += 1; user.show_dl_btn = true; }} />
<SubmissionStatus work={w} user={user} />
</td>
<td>
{#await getRepositories(w.id, user.id) then repos}
@ -90,7 +82,6 @@
<a
href="/api/users/{user.id}/works/{w.id}/download"
class="btn btn-sm btn-dark"
class:disabled={!user.show_dl_btn}
title="Télécharger la tarball du rendu"
>
<i class="bi bi-download"></i>