qa: Refactor layout
This commit is contained in:
parent
859b6a318e
commit
c13da8b574
19 changed files with 425 additions and 295 deletions
52
qa/ui/src/lib/components/ExerciceHeader.svelte
Normal file
52
qa/ui/src/lib/components/ExerciceHeader.svelte
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<script>
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Icon,
|
||||||
|
} from 'sveltestrap';
|
||||||
|
|
||||||
|
import { themes, themesIdx } from '$lib/stores/themes';
|
||||||
|
|
||||||
|
export let theme = null;
|
||||||
|
export let exercice = {};
|
||||||
|
export let query_selected = null;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
{#if query_selected}
|
||||||
|
<Button
|
||||||
|
class="float-start"
|
||||||
|
color="link"
|
||||||
|
on:click={() => goto(theme?`themes/${theme.id}/${exercice.id}`:`exercices/${exercice.id}`)}
|
||||||
|
>
|
||||||
|
<Icon name="chevron-left" />
|
||||||
|
</Button>
|
||||||
|
{:else if theme}
|
||||||
|
<Button
|
||||||
|
class="float-start"
|
||||||
|
color="link"
|
||||||
|
on:click={() => goto('themes/' + theme.id)}
|
||||||
|
>
|
||||||
|
<Icon name="chevron-left" />
|
||||||
|
</Button>
|
||||||
|
{:else}
|
||||||
|
<Button
|
||||||
|
class="float-start"
|
||||||
|
color="link"
|
||||||
|
on:click={() => goto('exercices/')}
|
||||||
|
>
|
||||||
|
<Icon name="chevron-left" />
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
{exercice.title}
|
||||||
|
{#if exercice.wip}
|
||||||
|
<Icon name="cone-striped" />
|
||||||
|
{/if}
|
||||||
|
{#if $themes.length && $themesIdx[exercice.id_theme]}
|
||||||
|
<small>
|
||||||
|
<a href="themes/{exercice.id_theme}" title={$themesIdx[exercice.id_theme].authors}>{$themesIdx[exercice.id_theme].name}</a>
|
||||||
|
</small>
|
||||||
|
<a href="../{$themesIdx[exercice.id_theme].urlid}/{exercice.urlid}" target="_self" class="float-right ml-2 btn btn-sm btn-info"><Icon name="play-fill" /> Site du challenge</a>
|
||||||
|
{/if}
|
||||||
|
</h2>
|
||||||
38
qa/ui/src/lib/components/ExerciceLayout.svelte
Normal file
38
qa/ui/src/lib/components/ExerciceLayout.svelte
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
Col,
|
||||||
|
Container,
|
||||||
|
Row,
|
||||||
|
} from 'sveltestrap';
|
||||||
|
|
||||||
|
import ExerciceHeader from '$lib/components/ExerciceHeader.svelte';
|
||||||
|
import QAItems from '$lib/components/QAItems.svelte';
|
||||||
|
|
||||||
|
export let theme = null;
|
||||||
|
export let exercice = {};
|
||||||
|
export let qaitems = null;
|
||||||
|
export let query_selected = null;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ExerciceHeader
|
||||||
|
{exercice}
|
||||||
|
{query_selected}
|
||||||
|
{theme}
|
||||||
|
/>
|
||||||
|
<Container fluid class="flex-fill d-flex">
|
||||||
|
<Row class="flex-fill">
|
||||||
|
<Col md={3} class="px-0 py-2" style="background: #e7e8e9">
|
||||||
|
{#key countCreation}
|
||||||
|
<QAItems
|
||||||
|
{exercice}
|
||||||
|
queries={qaitems}
|
||||||
|
{query_selected}
|
||||||
|
{theme}
|
||||||
|
/>
|
||||||
|
{/key}
|
||||||
|
</Col>
|
||||||
|
<Col md={9} class="d-flex flex-column py-2">
|
||||||
|
<slot></slot>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Container>
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
<script>
|
|
||||||
import { goto } from '$app/navigation';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Col,
|
|
||||||
Container,
|
|
||||||
Icon,
|
|
||||||
Row,
|
|
||||||
Table,
|
|
||||||
} from 'sveltestrap';
|
|
||||||
|
|
||||||
import QAItems from '$lib/components/QAItems.svelte';
|
|
||||||
import QAItem from '$lib/components/QAItem.svelte';
|
|
||||||
import QANewItem from '$lib/components/QANewItem.svelte';
|
|
||||||
import { themes, themesIdx } from '$lib/stores/themes';
|
|
||||||
|
|
||||||
if ($themes.length == 0) {
|
|
||||||
themes.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
export let theme_id = null;
|
|
||||||
export let exercice = {};
|
|
||||||
let query_selected = null;
|
|
||||||
let countCreation = 0;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<h2>
|
|
||||||
{#if query_selected}
|
|
||||||
<Button
|
|
||||||
class="float-start"
|
|
||||||
color="link"
|
|
||||||
on:click={() => query_selected = null}
|
|
||||||
>
|
|
||||||
<Icon name="chevron-left" />
|
|
||||||
</Button>
|
|
||||||
{:else if theme_id}
|
|
||||||
<Button
|
|
||||||
class="float-start"
|
|
||||||
color="link"
|
|
||||||
on:click={() => goto('themes/' + theme_id)}
|
|
||||||
>
|
|
||||||
<Icon name="chevron-left" />
|
|
||||||
</Button>
|
|
||||||
{:else}
|
|
||||||
<Button
|
|
||||||
class="float-start"
|
|
||||||
color="link"
|
|
||||||
on:click={() => goto('exercices/')}
|
|
||||||
>
|
|
||||||
<Icon name="chevron-left" />
|
|
||||||
</Button>
|
|
||||||
{/if}
|
|
||||||
{exercice.title}
|
|
||||||
{#if exercice.wip}
|
|
||||||
<Icon name="cone-striped" />
|
|
||||||
{/if}
|
|
||||||
{#if $themes.length && $themesIdx[exercice.id_theme]}
|
|
||||||
<small>
|
|
||||||
<a href="themes/{exercice.id_theme}" title={$themesIdx[exercice.id_theme].authors}>{$themesIdx[exercice.id_theme].name}</a>
|
|
||||||
</small>
|
|
||||||
<a href="../{$themesIdx[exercice.id_theme].urlid}/{exercice.urlid}" target="_self" class="float-right ml-2 btn btn-sm btn-info"><Icon name="play-fill" /> Site du challenge</a>
|
|
||||||
{/if}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<Container fluid class="flex-fill d-flex">
|
|
||||||
<Row class="flex-fill">
|
|
||||||
<Col md={3} class="px-0 py-2" style="background: #e7e8e9">
|
|
||||||
{#key countCreation}
|
|
||||||
<QAItems
|
|
||||||
bind:query_selected={query_selected}
|
|
||||||
{exercice}
|
|
||||||
/>
|
|
||||||
{/key}
|
|
||||||
</Col>
|
|
||||||
<Col md={9} class="d-flex flex-column py-2">
|
|
||||||
{#if query_selected}
|
|
||||||
<QAItem
|
|
||||||
bind:query_selected={query_selected}
|
|
||||||
on:update-queries={() => countCreation++}
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<Row class="mb-3">
|
|
||||||
<div
|
|
||||||
class="col-md-6"
|
|
||||||
style="overflow-y: auto; max-height: 40vh;"
|
|
||||||
>
|
|
||||||
{@html exercice.statement.replace("$FILES$", "../files")}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="col-md-6"
|
|
||||||
style="overflow-y: auto; max-height: 40vh;"
|
|
||||||
>
|
|
||||||
{@html exercice.overview.replace("$FILES$", "../files")}
|
|
||||||
</div>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<QANewItem
|
|
||||||
{exercice}
|
|
||||||
on:new-query={() => countCreation++}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Container>
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { goto, invalidate } from '$app/navigation';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
|
|
@ -20,19 +20,19 @@
|
||||||
import { ToastsStore } from '$lib/stores/toasts';
|
import { ToastsStore } from '$lib/stores/toasts';
|
||||||
import { viewIdx } from '$lib/stores/todo';
|
import { viewIdx } from '$lib/stores/todo';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
export let theme = null;
|
||||||
|
export let exercice = null;
|
||||||
export let query_selected;
|
export let query;
|
||||||
|
|
||||||
let query_commentsP;
|
let query_commentsP;
|
||||||
let thumbs = [];
|
let thumbs = [];
|
||||||
let thumb_me = [];
|
let thumb_me = [];
|
||||||
let has_comments = false;
|
let has_comments = false;
|
||||||
$: updateComments(query_selected)
|
$: updateComments(query)
|
||||||
|
|
||||||
function updateComments(query_selected) {
|
function updateComments(query) {
|
||||||
if (query_selected) {
|
if (query) {
|
||||||
query_commentsP = getQAComments(query_selected.id);
|
query_commentsP = getQAComments(query.id);
|
||||||
query_commentsP.then((comments) => {
|
query_commentsP.then((comments) => {
|
||||||
thumbs = [];
|
thumbs = [];
|
||||||
thumb_me = [];
|
thumb_me = [];
|
||||||
|
|
@ -65,8 +65,8 @@
|
||||||
let submissionInProgress = false;
|
let submissionInProgress = false;
|
||||||
function addComment() {
|
function addComment() {
|
||||||
submissionInProgress = true;
|
submissionInProgress = true;
|
||||||
newComment.save(query_selected.id).then(() => {
|
newComment.save(query.id).then(() => {
|
||||||
query_commentsP = getQAComments(query_selected.id);
|
query_commentsP = getQAComments(query.id);
|
||||||
newComment = new QAComment();
|
newComment = new QAComment();
|
||||||
submissionInProgress = false;
|
submissionInProgress = false;
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
|
@ -78,8 +78,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateQA() {
|
function updateQA() {
|
||||||
query_selected.save().then(() => {
|
query.save().then(() => {
|
||||||
dispatch("update-queries");
|
invalidate(`api/exercices/${exercice.id}/qa`);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
ToastsStore.addErrorToast({
|
ToastsStore.addErrorToast({
|
||||||
msg: err,
|
msg: err,
|
||||||
|
|
@ -88,9 +88,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function solveQA() {
|
function solveQA() {
|
||||||
query_selected.solved = new Date();
|
query.solved = new Date();
|
||||||
query_selected.save().then(() => {
|
query.save().then(() => {
|
||||||
dispatch("update-queries");
|
invalidate(`api/exercices/${exercice.id}/qa`);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
ToastsStore.addErrorToast({
|
ToastsStore.addErrorToast({
|
||||||
msg: err,
|
msg: err,
|
||||||
|
|
@ -99,9 +99,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function reopenQA() {
|
function reopenQA() {
|
||||||
query_selected.solved = null;
|
query.solved = null;
|
||||||
query_selected.save().then(() => {
|
query.save().then(() => {
|
||||||
dispatch("update-queries");
|
invalidate(`api/exercices/${exercice.id}/qa`);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
ToastsStore.addErrorToast({
|
ToastsStore.addErrorToast({
|
||||||
msg: err,
|
msg: err,
|
||||||
|
|
@ -110,9 +110,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeQA() {
|
function closeQA() {
|
||||||
query_selected.closed = new Date();
|
query.closed = new Date();
|
||||||
query_selected.save().then(() => {
|
query.save().then(() => {
|
||||||
dispatch("update-queries");
|
invalidate(`api/exercices/${exercice.id}/qa`);
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
ToastsStore.addErrorToast({
|
ToastsStore.addErrorToast({
|
||||||
msg: err,
|
msg: err,
|
||||||