add compte rendu export and fields
This commit is contained in:
parent
ff4bd2a868
commit
3d22b1f50f
@ -19,7 +19,8 @@
|
||||
<strong>{{ i + 1 }}) {{ s.title }}</strong>
|
||||
|
||||
<p class="is-small">
|
||||
{{ s.duration }} min, par {{ s.author }}. Reste: {{ resteTopicMinutes(s) }}. Passé: {{ round(s.spentSeconds) }}.
|
||||
{{ s.duration }} min, par {{ s.author }}. Reste: {{ resteTopicMinutes(s) }}.
|
||||
Passé: {{ round(s.spentSeconds) }}.
|
||||
</p>
|
||||
<p *ngIf="s.finished">🎉</p>
|
||||
</li>
|
||||
@ -34,17 +35,22 @@
|
||||
<h2>
|
||||
Texte du pad
|
||||
</h2>
|
||||
<textarea class="textarea mx-2 is-full" [(ngModel)]="pasteLand" id="pasteland"
|
||||
<textarea name="note" id="pasteland" cols="30" rows="10" class="textarea mx-2 is-full" [(ngModel)]="pasteLand"
|
||||
id="pasteland"
|
||||
(ngModelChange)="parseTheListOfTopicsInPasteLand()"></textarea>
|
||||
<h2>
|
||||
Compte rendu
|
||||
Compte rendu du {{ (today) | date:'yyyy-MM-dd'}}
|
||||
</h2>
|
||||
<p>
|
||||
{{buildCompteRendu()}}
|
||||
</p>
|
||||
<pre>
|
||||
{{buildCompteRendu()}}
|
||||
</pre>
|
||||
<button class="btn is-primary" (click)="copyCompteRenduToClipboard()">
|
||||
copier
|
||||
</button>
|
||||
<button class="btn is-primary" (click)="downloadCompteRendu()">
|
||||
télécharger le compte rendu
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="liens">
|
||||
@ -66,11 +72,11 @@
|
||||
</div>
|
||||
<div class="explications">
|
||||
<p>
|
||||
|
||||
{{statsExplication}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="debug" *ngIf="showDebug">
|
||||
debug:
|
||||
<pre>
|
||||
@ -96,21 +102,38 @@
|
||||
<p>Reste: {{ countRemainingMinutes(subjects[currentSubjectId]) }} min</p>
|
||||
<p>avancement: {{ getPercentProgressTimeForTopic(subjects[currentSubjectId]) }} %</p>
|
||||
|
||||
<p>Début: {{ startTime }}</p>
|
||||
<p>Fin: {{ endTime }}</p>
|
||||
<hr>
|
||||
<div class="compte-rendu-infos">
|
||||
<label for="scribe">scribe</label>
|
||||
<input type="text" id="scribe" [(ngModel)]="scribe">
|
||||
<br>
|
||||
<label for="presents">{{countLinesInPresent()}}présents</label>
|
||||
<textarea name="presents" id="note" cols="30" rows="10" id="presents" [(ngModel)]="presents"></textarea>
|
||||
<br>
|
||||
<label for="début">Début</label>
|
||||
<input name="presents" id="début" [(ngModel)]="startTime"/>
|
||||
<br>
|
||||
<label for="fin">Fin</label>
|
||||
<input name="presents" id="fin" [(ngModel)]="endTime"/>
|
||||
|
||||
<button class="btn btn-primary" (click)="previousSubject()">
|
||||
précédent
|
||||
</button>
|
||||
<button class="btn is-primary" (click)="nextSubject()">
|
||||
suivant
|
||||
</button>
|
||||
<button class="btn is-success" (click)="finishTopic(currentSubjectId)">
|
||||
fini
|
||||
</button>
|
||||
<button class="btn btn-primary" (click)="updateProgressEveryPeriod()">
|
||||
up temps
|
||||
</button>
|
||||
</div>
|
||||
<div class="actions">
|
||||
|
||||
<p>Début: {{ startTime }}, Fin: {{ endTime }}. Durée: {{round(getMinutesBetweenTwoDates(startDate,endDate))}}</p>
|
||||
|
||||
<button class="btn btn-primary" (click)="previousSubject()">
|
||||
précédent
|
||||
</button>
|
||||
<button class="btn is-primary" (click)="nextSubject()">
|
||||
suivant
|
||||
</button>
|
||||
<button class="btn is-success" (click)="finishTopic(currentSubjectId)">
|
||||
fini
|
||||
</button>
|
||||
<button class="btn btn-primary" (click)="updateProgressEveryPeriod()">
|
||||
up temps
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -164,17 +164,35 @@ main {
|
||||
border-left-color: #00b89c;
|
||||
}
|
||||
}
|
||||
label{
|
||||
margin-right: 2ch;
|
||||
margin-top: 1rem;
|
||||
min-width: 10rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn{
|
||||
cursor: pointer;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border: solid 1px slategray;
|
||||
border-radius: 0.5rem;
|
||||
float:left;
|
||||
margin-right: 2ch;
|
||||
display: inline-block;
|
||||
}
|
||||
pre{
|
||||
padding: 0.5rem;
|
||||
background: lightslategrey;
|
||||
}
|
||||
|
||||
.is-clickable{
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
&.subject{
|
||||
background: rgba(170, 210, 199,0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 650px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
|
@ -30,6 +30,11 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
startTime: string = "20:30";
|
||||
// startTime: string = "17:00";
|
||||
endTime: string = "22:00";
|
||||
today: any = new Date();
|
||||
// champs habituels pour le compte rendu:
|
||||
scribe: string = 'tykayn';
|
||||
presents: string = '- tykayn';
|
||||
|
||||
pasteLand: string = "* Présentation du suivi sur Nextcloud - 5min (tykayn)\n" +
|
||||
"* Réduction de bus factor - 5min (tykayn)\n" +
|
||||
"* Réunion avec Wikimedia France - 5min (tykayn)\n" +
|
||||
@ -40,9 +45,11 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
hints: string = "";
|
||||
|
||||
showDebug: boolean = true;
|
||||
private startDate: Date = new Date();
|
||||
private endDate: Date = new Date();
|
||||
startDate: Date = new Date();
|
||||
endDate: Date = new Date();
|
||||
private topicChangeDate: Date = new Date();
|
||||
private timekeeper: any;
|
||||
private animator: any;
|
||||
|
||||
|
||||
updateTopicChangeDate(): void {
|
||||
@ -54,9 +61,10 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
this.subjects[this.currentSubjectId].spentSeconds += timeDifferenceInSeconds;
|
||||
this.topicChangeDate = currentTime;
|
||||
}
|
||||
round(val:number){
|
||||
|
||||
round(val: number) {
|
||||
if (val < 60) {
|
||||
return Math.round(val) +' s'
|
||||
return Math.round(val) + ' s'
|
||||
}
|
||||
return (Math.round(val / 60) * 60) + ' min'
|
||||
}
|
||||
@ -73,12 +81,13 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
if (boom[0]) {
|
||||
accumulatedDuration += this.findMinutesDurationInDescription(topic) | 0
|
||||
|
||||
|
||||
newTopics.push({
|
||||
id: ii,
|
||||
title: boom[0],
|
||||
duration: 15,
|
||||
spentSeconds: 0,
|
||||
author: '',
|
||||
author: this.findAuthorInDescription(topic),
|
||||
notes: '',
|
||||
finished: false,
|
||||
startDate: this.getStartDateAfterDuration(accumulatedDuration + ''),
|
||||
@ -214,30 +223,30 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
makeStatisticsOnTopicsSpentSeconds() {
|
||||
let totalSeconds = 0;
|
||||
for (const topic of this.subjects) {
|
||||
totalSeconds += topic.spentSeconds;
|
||||
}
|
||||
|
||||
let averageSeconds = totalSeconds / this.subjects.length;
|
||||
|
||||
let longestTopic = this.subjects[0];
|
||||
let longestSeconds = longestTopic.spentSeconds;
|
||||
for (const topic of this.subjects) {
|
||||
if (topic.spentSeconds > longestSeconds) {
|
||||
longestSeconds = topic.spentSeconds;
|
||||
longestTopic = topic;
|
||||
let totalSeconds = 0;
|
||||
for (const topic of this.subjects) {
|
||||
totalSeconds += topic.spentSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
let shortestTopic = this.subjects[0];
|
||||
let shortestSeconds = shortestTopic.spentSeconds;
|
||||
for (const topic of this.subjects) {
|
||||
if (topic.spentSeconds < shortestSeconds) {
|
||||
shortestSeconds = topic.spentSeconds;
|
||||
shortestTopic = topic;
|
||||
let averageSeconds = totalSeconds / this.subjects.length;
|
||||
|
||||
let longestTopic = this.subjects[0];
|
||||
let longestSeconds = longestTopic.spentSeconds;
|
||||
for (const topic of this.subjects) {
|
||||
if (topic.spentSeconds > longestSeconds) {
|
||||
longestSeconds = topic.spentSeconds;
|
||||
longestTopic = topic;
|
||||
}
|
||||
}
|
||||
|
||||
let shortestTopic = this.subjects[0];
|
||||
let shortestSeconds = shortestTopic.spentSeconds;
|
||||
for (const topic of this.subjects) {
|
||||
if (topic.spentSeconds < shortestSeconds) {
|
||||
shortestSeconds = topic.spentSeconds;
|
||||
shortestTopic = topic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.statsExplication = `Total spent seconds: ${totalSeconds}\nAverage spent seconds: ${averageSeconds}\nLongest topic: ${longestTopic.title} (${longestSeconds} seconds)\nShortest topic: ${shortestTopic.title} (${shortestSeconds} seconds)`;
|
||||
@ -249,21 +258,87 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
this.updateTopicChangeDate()
|
||||
}
|
||||
|
||||
compteRendu:string = ''
|
||||
compteRendu: string = ''
|
||||
|
||||
formatDateYMD(date: Date) {
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
|
||||
buildCompteRendu(){
|
||||
let compteRendu = 'Compte rendu :\n\n';
|
||||
buildCompteRendu() {
|
||||
let compteRendu = `Compte rendu du ${this.formatDateYMD(this.today)}\n`;
|
||||
compteRendu += ` début: ${this.startTime}, fin:${this.endTime}.\n`;
|
||||
compteRendu += ` Présents: ${this.formatPresentLines()}.\n`;
|
||||
if (this.scribe) {
|
||||
compteRendu += ` Scribe: ${this.scribe}.\n`;
|
||||
}
|
||||
if (this.timekeeper) {
|
||||
compteRendu += ` Gardien du temps: ${this.timekeeper}.\n`;
|
||||
}
|
||||
if (this.animator) {
|
||||
compteRendu += ` Animation: ${this.animator}.\n`;
|
||||
}
|
||||
for (const topic of this.subjects) {
|
||||
compteRendu += `Sujet ${topic.id + 1} : ${topic.title}\n`;
|
||||
compteRendu += `Durée : ${topic.duration} minutes\n`;
|
||||
compteRendu += `Temps écoulé : ${this.resteTopicMinutes(topic)}\n\n`;
|
||||
compteRendu += `* ${topic.title}-`;
|
||||
compteRendu += ` ${topic.duration} min`;
|
||||
compteRendu += ` (${topic.author})\n`;
|
||||
compteRendu += ` \n${topic.notes}\n`;
|
||||
compteRendu += `Temps écoulé : ${this.round(topic.spentSeconds)}\n\n`;
|
||||
}
|
||||
this.compteRendu = compteRendu
|
||||
return compteRendu
|
||||
}
|
||||
copyCompteRenduToClipboard() {
|
||||
|
||||
/**
|
||||
* returns each present person for each line with a dash at the beggining if missing
|
||||
*/
|
||||
formatPresentLines(){
|
||||
let lines = ''
|
||||
if (this.presents) {
|
||||
lines += this.presents.split('\n').map(line => {
|
||||
if(!line.length){
|
||||
return '';
|
||||
}
|
||||
if (!line.startsWith('- ')) {
|
||||
return `- ${line}`;
|
||||
}
|
||||
return line;
|
||||
}).join('\n') + '\n'
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
copyCompteRenduToClipboard() {
|
||||
navigator.clipboard.writeText(this.compteRendu);
|
||||
}
|
||||
|
||||
|
||||
private findAuthorInDescription(topic: string): string {
|
||||
let authorRegex = /\(([^)]+)\)/g;
|
||||
let matches = authorRegex.exec(topic);
|
||||
if (matches) {
|
||||
return matches[1];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
countLinesInPresent() {
|
||||
return this.presents.split('\n').length;
|
||||
}
|
||||
|
||||
downloadCompteRendu() {
|
||||
let fichier = new Blob([this.buildCompteRendu()], {type: 'text/plain'});
|
||||
let lien = document.createElement('a');
|
||||
lien.setAttribute('href', window.URL.createObjectURL(fichier));
|
||||
lien.setAttribute('download', 'compte-rendu.txt');
|
||||
lien.click();
|
||||
}
|
||||
|
||||
getMinutesBetweenTwoDates(date1: Date, date2: Date) {
|
||||
return Math.floor((date2.getTime() - date1.getTime()) / 60000);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user