291 lines
13 KiB
Svelte
291 lines
13 KiB
Svelte
<script>
|
|
import {
|
|
Alert,
|
|
Badge,
|
|
Button,
|
|
Card,
|
|
CardBody,
|
|
CardHeader,
|
|
CardText,
|
|
Col,
|
|
Icon,
|
|
Row,
|
|
Spinner,
|
|
} from '@sveltestrap/sveltestrap';
|
|
|
|
import ExerciceDownloads from '$lib/components/ExerciceDownloads.svelte';
|
|
import ExerciceFlags from '$lib/components/ExerciceFlags.svelte';
|
|
import ExerciceHints from '$lib/components/ExerciceHints.svelte';
|
|
import ExerciceSolved from '$lib/components/ExerciceSolved.svelte';
|
|
import ExerciceVideo from '$lib/components/ExerciceVideo.svelte';
|
|
import ResolutionModal from '$lib/components/ResolutionModal.svelte';
|
|
|
|
import { current_exercice } from '$lib/stores/exercices';
|
|
import { my } from '$lib/stores/my';
|
|
import { current_theme } from '$lib/stores/themes';
|
|
import { settings } from '$lib/stores/settings';
|
|
|
|
import { waitDiff, waitInProgress } from '$lib/wait.js';
|
|
|
|
let solved = {};
|
|
let openResolution = false;
|
|
|
|
async function askProgressReset() {
|
|
waitInProgress.set(true);
|
|
const response = await fetch(
|
|
"reset_progress",
|
|
{
|
|
method: "POST",
|
|
headers: {'Accept': 'application/json'},
|
|
body: JSON.stringify({"eid": $current_exercice.id}),
|
|
}
|
|
);
|
|
if (response.status < 300) {
|
|
waitDiff(13, $my.exercices[$current_exercice.id]);
|
|
} else {
|
|
data = await response.json();
|
|
waitInProgress.set(false);
|
|
alert("Quelque chose s'est mal passé : " + data.errmsg);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
{#if $current_exercice}
|
|
<Card body class="niceborder text-indent my-3">
|
|
{#if $current_theme.locked}
|
|
<div style="position: absolute; z-index: 0; top: 0; bottom: 0; left: 0; right: 0;" class="d-flex justify-content-center align-items-center">
|
|
<div style="transform: rotate(-25deg)">
|
|
<div class="display-3 font-weight-bolder border border-danger text-danger px-3 py-1" style="opacity: 0.5; border-radius: 20px; border-width: 5px !important; font-family: 'Courier New'">
|
|
CONFIDENTIEL
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
<h3 class="display-4">{$current_exercice.title}</h3>
|
|
<div>
|
|
{#each $current_exercice.tags as tag, index}
|
|
<Badge href="tags/{tag}" pill color="secondary" class="mx-1 mb-2" >#{tag}</Badge>
|
|
{/each}
|
|
</div>
|
|
{#if !$my || !$my.exercices[$current_exercice.id]}
|
|
<p class="lead text-justify">{@html $current_exercice.headline}</p>
|
|
{:else}
|
|
{#if $my.exercices[$current_exercice.id].wip}
|
|
<Alert color="warning">
|
|
<Icon name="cone-striped" />
|
|
<strong>
|
|
Cette étape est marquée comme étant en cours d'élaboration.
|
|
</strong>
|
|
Elle n'est pas prête à être tentée. Vous devriez directement passer à l'étape suivante.
|
|
</Alert>
|
|
{/if}
|
|
<p class="lead text-justify">{@html $my.exercices[$current_exercice.id].statement}</p>
|
|
{#if $my.exercices[$current_exercice.id].issue}
|
|
<Alert color="{$my.exercices[$current_exercice.id].issuekind}">
|
|
{@html $my.exercices[$current_exercice.id].issue}
|
|
</Alert>
|
|
{/if}
|
|
{/if}
|
|
<hr class="mt-0 mb-4">
|
|
<Row>
|
|
<Col>
|
|
<Row class="level" cols={{xs:2, md:3, xl:4}}>
|
|
<Col>
|
|
<div class="level-item">
|
|
{#if $settings.discountedFactor > 0 && $my && $my.exercices[$current_exercice.id]}
|
|
<div class="heading">
|
|
Cote
|
|
</div>
|
|
{:else}
|
|
<div class="heading">
|
|
Gain
|
|
</div>
|
|
{/if}
|
|
<div class="value">
|
|
{#if $settings.discountedFactor && $current_exercice.solved}
|
|
<!-- This display the number of points gained by the team if it validates the exercice (current teams have more points than that) -->
|
|
{Math.trunc($current_exercice.gain * (1-$settings.discountedFactor*$current_exercice.solved)*10)/10} {$current_exercice.gain==1?"point":"points"}
|
|
{:else}
|
|
{$current_exercice.gain} {$current_exercice.gain==1?"point":"points"}
|
|
{/if}
|
|
</div>
|
|
{#if $settings.firstBlood && $current_exercice.solved < 1}
|
|
<div class="text-muted">
|
|
<em>+{$settings.firstBlood * 100}% (prem's)</em>
|
|
</div>
|
|
{:else if $settings.discountedFactor > 0 && $my && $my.exercices[$current_exercice.id]}
|
|
<div class="text-muted">
|
|
<em>initialement {$current_exercice.gain} {$current_exercice.gain==1?"point":"points"}</em>
|
|
</div>
|
|
{/if}
|
|
{#if $current_exercice.curcoeff != 1.0 || $settings.exerciceCurrentCoefficient != 1.0}
|
|
<div class="text-muted">
|
|
<em>{#if $current_exercice.curcoeff * $settings.exerciceCurrentCoefficient > 1}+{Math.round(($current_exercice.curcoeff * $settings.exerciceCurrentCoefficient - 1) * 100)}{:else}-{Math.round((1-($current_exercice.curcoeff * $settings.exerciceCurrentCoefficient)) * 100)}{/if}% (bonus)</em>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</Col>
|
|
<Col class="d-none d-md-block">
|
|
<div class="level-item">
|
|
<div class="heading">
|
|
Tenté par
|
|
</div>
|
|
<div class="value">
|
|
{#if !$current_exercice.tried}
|
|
aucune équipe
|
|
{:else}
|
|
{$current_exercice.tried} {$current_exercice.tried == 1?"équipe":"équipes"}
|
|
{#if $my && $my.exercices[$current_exercice.id] && $my.exercices[$current_exercice.id].total_tries}
|
|
(cumulant {$my.exercices[$current_exercice.id].total_tries} {$my.exercices[$current_exercice.id].total_tries == 1?"tentative":"tentatives"})
|
|
{/if}
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</Col>
|
|
<Col class="d-none d-md-block">
|
|
<div class="level-item">
|
|
<div class="heading">
|
|
Résolu par
|
|
</div>
|
|
<div class="value">
|
|
{#if !$current_exercice.solved}
|
|
aucune équipe
|
|
{:else}
|
|
{$current_exercice.solved} {$current_exercice.solved == 1?"équipe":"équipes"}
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</Col>
|
|
<Col class="d-block d-md-none">
|
|
<div class="level-item">
|
|
<div class="heading">
|
|
{#if !$current_exercice.solved}
|
|
Tenté par
|
|
{:else}
|
|
Résolu par
|
|
{/if}
|
|
</div>
|
|
<div class="value">
|
|
{#if !$current_exercice.solved}
|
|
{#if !$current_exercice.tried}
|
|
aucune équipe
|
|
{:else}
|
|
{$current_exercice.tried} {$current_exercice.tried == 1?"équipe":"équipes"}
|
|
{#if $my && $my.exercices[$current_exercice.id] && $my.exercices[$current_exercice.id].total_tries}
|
|
(cumulant {$my.exercices[$current_exercice.id].total_tries} {$my.exercices[$current_exercice.id].total_tries == 1?"tentative":"tentatives"})
|
|
{/if}
|
|
{/if}
|
|
{:else}
|
|
{$current_exercice.solved} {$current_exercice.solved == 1?"équipe":"équipes"}
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</Col>
|
|
</Row>
|
|
</Col>
|
|
{#if $my && $my.team_id}
|
|
<Col xs="auto" class="d-flex flex-column justify-content-between">
|
|
{#if $settings.acceptNewIssue}
|
|
<a href="issues/?eid={$current_exercice.id}" class="btn btn-sm btn-warning">
|
|
<Icon name="bug" />
|
|
Rapporter une anomalie sur ce défi
|
|
</a>
|
|
{/if}
|
|
{#if $settings.QAenabled}
|
|
<a href="qa/exercices/{$current_exercice.id}" class="btn btn-sm btn-info" target="_self">
|
|
<Icon name="bug" />
|
|
Voir les éléments QA sur ce défi
|
|
</a>
|
|
{/if}
|
|
{#if $settings.wip && $settings.canResetProgress}
|
|
<Button size="sm" color="dark" on:click={askProgressReset} disabled={!$my.exercices[$current_exercice.id].solved_time || $waitInProgress}>
|
|
{#if $waitInProgress}
|
|
<Spinner size="sm" />
|
|
{:else}
|
|
<Icon name="skip-start-fill" />
|
|
{/if}
|
|
Effacer ma progression sur ce défi
|
|
</Button>
|
|
{/if}
|
|
</Col>
|
|
{/if}
|
|
</Row>
|
|
</Card>
|
|
|
|
{#if $my && $my.exercices[$current_exercice.id]}
|
|
<Row class="mt-4">
|
|
<Col lg="6" class="mb-5">
|
|
{#if $my.exercices[$current_exercice.id].files}
|
|
<ExerciceDownloads
|
|
files={$my.exercices[$current_exercice.id].files}
|
|
/>
|
|
{/if}
|
|
{#if $my.exercices[$current_exercice.id].hints}
|
|
<ExerciceHints
|
|
locked_theme={$current_theme.locked}
|
|
exercice={$my.exercices[$current_exercice.id]}
|
|
hints={$my.exercices[$current_exercice.id].hints}
|
|
/>
|
|
{/if}
|
|
</Col>
|
|
<Col lg="6" class="mb-5">
|
|
{#if $my.exercices[$current_exercice.id].flags && ($my.exercices[$current_exercice.id].non_found_flags > 0 || !$my.exercices[$current_exercice.id].solved_rank) && !solved[$current_exercice.id]}
|
|
{#if $current_theme.locked}
|
|
<Card class="border-danger mb-2">
|
|
<CardHeader class="bg-black text-light">
|
|
<Icon name="lock-fill" />
|
|
Faire son rapport
|
|
</CardHeader>
|
|
<CardBody>
|
|
<p>
|
|
Ce scénario n'est pas accessible !
|
|
</p>
|
|
<p>
|
|
Vous ne pouvez pas compléter son rapport.
|
|
</p>
|
|
</CardBody>
|
|
</Card>
|
|
{:else}
|
|
<ExerciceFlags
|
|
exercice={$my.exercices[$current_exercice.id]}
|
|
bind:forcesolved={solved[$current_exercice.id]}
|
|
flags={$my.exercices[$current_exercice.id].flags}
|
|
readonly={$current_exercice.disabled}
|
|
/>
|
|
{/if}
|
|
{/if}
|
|
{#if $my.exercices[$current_exercice.id].solved_rank || solved[$current_exercice.id]}
|
|
<ExerciceSolved
|
|
theme={$current_theme}
|
|
exercice={$my.exercices[$current_exercice.id]}
|
|
/>
|
|
{/if}
|
|
{#if $my.exercices[$current_exercice.id].resolution || $my.exercices[$current_exercice.id].video_uri}
|
|
<Card class="border-success mb-2">
|
|
<CardHeader class="bg-success text-light d-flex justify-content-between">
|
|
<div>
|
|
<Icon name="laptop-fill" />
|
|
Solution du défi
|
|
</div>
|
|
{#if $my.exercices[$current_exercice.id].resolution}
|
|
<Button color="success" size="sm" on:click={() => openResolution = true}>
|
|
<Icon name="arrows-angle-expand" />
|
|
</Button>
|
|
<ResolutionModal exercice={$current_exercice} bind:open={openResolution} resolution={$my.exercices[$current_exercice.id].resolution} />
|
|
{/if}
|
|
</CardHeader>
|
|
{#if $my.exercices[$current_exercice.id].resolution}
|
|
<CardBody>
|
|
{@html $my.exercices[$current_exercice.id].resolution}
|
|
</CardBody>
|
|
{/if}
|
|
{#if $my.exercices[$current_exercice.id].video_uri}
|
|
<ExerciceVideo uri={$my.exercices[$current_exercice.id].video_uri} />
|
|
{/if}
|
|
</Card>
|
|
{/if}
|
|
</Col>
|
|
</Row>
|
|
{/if}
|
|
{/if}
|