project blueprint - optional steps working
This commit is contained in:
parent
595c275100
commit
8da0fb0e36
30 changed files with 296 additions and 127 deletions
|
|
@ -6,7 +6,7 @@ Optionalsteps: industrialIdeation, physicalSample
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Currentstep: brief
|
Currentstep: extendedBrief
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
Title: Brief client
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepname: clientBrief
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepindex: 1
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: 8B7d4RgY8eFqvqOB
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Briefclientpdf:
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Description:
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Briefclientimages:
|
||||||
13
public/content/projects/_drafts/test/2_proposal/proposal.txt
Normal file
13
public/content/projects/_drafts/test/2_proposal/proposal.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
Title: Offre commerciale
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepname: proposal
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepindex: 2
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: AORTte4et35lhTXL
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
Title: Brief enrichi
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepname: extended-brief
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepindex: 3
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: oBp6AlnPTY1xpfNU
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
Title: Échantillon virtuel
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepname: virtualSample
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepindex: 5
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: KvcDJf8bfJXQnxML
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
Title: Idéation industrielle
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepname: industrialIdeation
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepindex: 4
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: jGfYrEyipW8esCwk
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
Title: Échantillon physique
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepname: physicalSample
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Stepindex: 6
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: IbgnF5QBMM0WsmRK
|
||||||
9
public/content/projects/_drafts/test/project.txt
Normal file
9
public/content/projects/_drafts/test/project.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
Title: test
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Client:
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Uuid: 96WmogVvmpMRmgzj
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
Title: Projet Test
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Client: - page://G418qZ4ABsoWFx4i
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Briefclientpdf:
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Description: Maecenas sed diam eget risus varius blandit sit amet non magna. Curabitur blandit tempus porttitor. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas faucibus mollis interdum.
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Briefclientimages:
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Pdf:
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Text:
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Uuid: Bdho8W2PQkSk1x21
|
|
||||||
|
|
@ -21,6 +21,9 @@ tabs:
|
||||||
columns:
|
columns:
|
||||||
- width: 1/1
|
- width: 1/1
|
||||||
fields:
|
fields:
|
||||||
|
stepName:
|
||||||
|
type: hidden
|
||||||
|
value: test
|
||||||
briefClientPdf:
|
briefClientPdf:
|
||||||
label: PDF
|
label: PDF
|
||||||
type: files
|
type: files
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,9 @@ options:
|
||||||
move: false
|
move: false
|
||||||
duplicate: false
|
duplicate: false
|
||||||
sort: false
|
sort: false
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
contentTab:
|
||||||
|
fields:
|
||||||
|
stepName:
|
||||||
|
type: hidden
|
||||||
|
|
|
||||||
11
public/site/blueprints/pages/industrial-ideation.yml
Normal file
11
public/site/blueprints/pages/industrial-ideation.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
title: Idéation industrielle
|
||||||
|
icon: light-bulb
|
||||||
|
image:
|
||||||
|
back: black
|
||||||
|
color: white
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
contentTab:
|
||||||
|
fields:
|
||||||
|
stepName:
|
||||||
|
type: hidden
|
||||||
11
public/site/blueprints/pages/physical-sample.yml
Normal file
11
public/site/blueprints/pages/physical-sample.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
title: Échantillon physique
|
||||||
|
icon: image
|
||||||
|
image:
|
||||||
|
back: black
|
||||||
|
color: white
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
contentTab:
|
||||||
|
fields:
|
||||||
|
stepName:
|
||||||
|
type: hidden
|
||||||
|
|
@ -8,15 +8,6 @@ tabs:
|
||||||
columns:
|
columns:
|
||||||
- width: 1/1
|
- width: 1/1
|
||||||
fields:
|
fields:
|
||||||
optionalSteps:
|
|
||||||
label: Étapes optionnelles
|
|
||||||
type: checkboxes
|
|
||||||
width: 1/2
|
|
||||||
columns: 2
|
|
||||||
options:
|
|
||||||
industrialIdeation: Idéation industrielle
|
|
||||||
physicalSample: Échantillon physique
|
|
||||||
help: Après modification, sauvegardez et rechargez la page pour mettre à jour la liste ci-dessous.
|
|
||||||
currentStep:
|
currentStep:
|
||||||
label: Étape en cours
|
label: Étape en cours
|
||||||
type: radio
|
type: radio
|
||||||
|
|
@ -43,11 +34,14 @@ tabs:
|
||||||
stepsSection:
|
stepsSection:
|
||||||
label: Étapes
|
label: Étapes
|
||||||
type: pages
|
type: pages
|
||||||
|
sortBy: stepIndex asc
|
||||||
templates:
|
templates:
|
||||||
- client-brief
|
- client-brief
|
||||||
- proposal
|
- proposal
|
||||||
- extended-brief
|
- extended-brief
|
||||||
- sample
|
- industrial-ideation
|
||||||
|
- virtual-sample
|
||||||
|
- physical-sample
|
||||||
|
|
||||||
# client:
|
# client:
|
||||||
# label: Client
|
# label: Client
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,9 @@ options:
|
||||||
move: false
|
move: false
|
||||||
duplicate: false
|
duplicate: false
|
||||||
sort: false
|
sort: false
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
contentTab:
|
||||||
|
fields:
|
||||||
|
stepName:
|
||||||
|
type: hidden
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,9 @@ options:
|
||||||
move: false
|
move: false
|
||||||
duplicate: false
|
duplicate: false
|
||||||
sort: false
|
sort: false
|
||||||
|
|
||||||
|
tabs:
|
||||||
|
contentTab:
|
||||||
|
fields:
|
||||||
|
stepName:
|
||||||
|
type: hidden
|
||||||
|
|
@ -1,37 +1,67 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return function($page) {
|
return function($page) {
|
||||||
if ($page->template() != "project") return;
|
if ($page->template() == "project") {
|
||||||
|
kirby()->impersonate('kirby');
|
||||||
$page->createChild([
|
|
||||||
'slug' => 'client-brief',
|
$brief = $page->createChild([
|
||||||
'template' => 'client-brief',
|
'slug' => 'client-brief',
|
||||||
'content' => [
|
'template' => 'client-brief',
|
||||||
'title' => 'Brief client'
|
'content' => [
|
||||||
]
|
'title' => 'Brief client',
|
||||||
]);
|
'stepName' => 'clientBrief',
|
||||||
|
'stepIndex' => 1
|
||||||
$page->createChild([
|
],
|
||||||
'slug' => 'proposal',
|
])->changeStatus('listed');
|
||||||
'template' => 'proposal',
|
|
||||||
'content' => [
|
$page->createChild([
|
||||||
'title' => 'Offre commerciale'
|
'slug' => 'proposal',
|
||||||
]
|
'template' => 'proposal',
|
||||||
]);
|
'content' => [
|
||||||
|
'title' => 'Offre commerciale',
|
||||||
$page->createChild([
|
'stepName' => 'proposal',
|
||||||
'slug' => 'extended-brief',
|
'stepIndex' => 2
|
||||||
'template' => 'extended-brief',
|
]
|
||||||
'content' => [
|
])->changeStatus('listed');
|
||||||
'title' => 'Brief enrichi'
|
|
||||||
]
|
$page->createChild([
|
||||||
]);
|
'slug' => 'extended-brief',
|
||||||
|
'template' => 'extended-brief',
|
||||||
$page->createChild([
|
'content' => [
|
||||||
'slug' => 'sample',
|
'title' => 'Brief enrichi',
|
||||||
'template' => 'sample',
|
'stepName' => 'extended-brief',
|
||||||
'content' => [
|
'stepIndex' => 3
|
||||||
'title' => 'Échantillon virtuel'
|
]
|
||||||
]
|
])->changeStatus('listed');
|
||||||
]);
|
|
||||||
|
$page->createChild([
|
||||||
|
'slug' => 'industrial-ideation',
|
||||||
|
'template' => 'industrial-ideation',
|
||||||
|
'content' => [
|
||||||
|
'title' => 'Idéation industrielle',
|
||||||
|
'stepName' => 'industrialIdeation',
|
||||||
|
'stepIndex' => 4
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$page->createChild([
|
||||||
|
'slug' => 'virtual-sample',
|
||||||
|
'template' => 'virtual-sample',
|
||||||
|
'content' => [
|
||||||
|
'title' => 'Échantillon virtuel',
|
||||||
|
'stepName' => 'virtualSample',
|
||||||
|
'stepIndex' => 5
|
||||||
|
]
|
||||||
|
])->changeStatus('listed');
|
||||||
|
|
||||||
|
$page->createChild([
|
||||||
|
'slug' => 'physical-sample',
|
||||||
|
'template' => 'physical-sample',
|
||||||
|
'content' => [
|
||||||
|
'title' => 'Échantillon physique',
|
||||||
|
'stepName' => 'physicalSample',
|
||||||
|
'stepIndex' => 6
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
0
public/site/models/client-brief.php
Normal file
0
public/site/models/client-brief.php
Normal file
|
|
@ -3,39 +3,12 @@
|
||||||
class ProjectPage extends Page {
|
class ProjectPage extends Page {
|
||||||
public function getSteps() {
|
public function getSteps() {
|
||||||
|
|
||||||
$steps = [
|
$steps = array_map(function($child) {
|
||||||
[
|
return [
|
||||||
'text' => '1. Brief',
|
'text' => $child['content']['title'],
|
||||||
'value' => 'brief'
|
'value' => $child['content']['stepname']
|
||||||
],
|
|
||||||
[
|
|
||||||
'text' => '2. Offre commerciale',
|
|
||||||
'value' => 'proposal'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'text' => '3. Brief enrichi',
|
|
||||||
'value' => 'extendedBrief'
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
if (str_contains($this->optionalSteps(), 'industrialIdeation')) {
|
|
||||||
$steps[] = [
|
|
||||||
'text' => '4. Idéation industrielle',
|
|
||||||
'value' => 'industrialIdeation'
|
|
||||||
];
|
];
|
||||||
}
|
}, $this->children()->toArray());
|
||||||
|
|
||||||
$steps[] = [
|
|
||||||
'text' => count($steps) + 1 . '. Échantillon virtuel',
|
|
||||||
'value' => 'virtualSample'
|
|
||||||
];
|
|
||||||
|
|
||||||
if (str_contains($this->optionalSteps(), 'physicalSample')) {
|
|
||||||
$steps[] = [
|
|
||||||
'text' => count($steps) + 1 . '.Échantillon physique',
|
|
||||||
'value' => 'physicalSample'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $steps;
|
return $steps;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
public/site/plugins/icons/index.js
Normal file
6
public/site/plugins/icons/index.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
panel.plugin("my/icons", {
|
||||||
|
icons: {
|
||||||
|
"light-bulb":
|
||||||
|
'<path d="M9.97308 18H14.0269C14.1589 16.7984 14.7721 15.8065 15.7676 14.7226C15.8797 14.6006 16.5988 13.8564 16.6841 13.7501C17.5318 12.6931 18 11.385 18 10C18 6.68629 15.3137 4 12 4C8.68629 4 6 6.68629 6 10C6 11.3843 6.46774 12.6917 7.31462 13.7484C7.40004 13.855 8.12081 14.6012 8.23154 14.7218C9.22766 15.8064 9.84103 16.7984 9.97308 18ZM14 20H10V21H14V20ZM5.75395 14.9992C4.65645 13.6297 4 11.8915 4 10C4 5.58172 7.58172 2 12 2C16.4183 2 20 5.58172 20 10C20 11.8925 19.3428 13.6315 18.2443 15.0014C17.624 15.7748 16 17 16 18.5V21C16 22.1046 15.1046 23 14 23H10C8.89543 23 8 22.1046 8 21V18.5C8 17 6.37458 15.7736 5.75395 14.9992ZM13 10.0048H15.5L11 16.0048V12.0048H8.5L13 6V10.0048Z"></path>',
|
||||||
|
},
|
||||||
|
});
|
||||||
4
public/site/plugins/icons/index.php
Normal file
4
public/site/plugins/icons/index.php
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
Kirby::plugin('adrienpayet/pochet-icons', [
|
||||||
|
'icons' => []
|
||||||
|
]);
|
||||||
|
|
@ -5,7 +5,9 @@ $project = [
|
||||||
'url' => $page->url(),
|
'url' => $page->url(),
|
||||||
'modified' => $page->modified('Y-MM-d'),
|
'modified' => $page->modified('Y-MM-d'),
|
||||||
'status' => $page->status(),
|
'status' => $page->status(),
|
||||||
'logo' => $page->client()->toPage()->logo()->toFile()->url()
|
'logo' => $page->client()->toPage()->logo()->toFile()->url(),
|
||||||
|
'currentStep' => $page->currentStep()->value(),
|
||||||
|
'steps' => $page->getSteps()
|
||||||
];
|
];
|
||||||
|
|
||||||
$data = array_merge($genericData, $project);
|
$data = array_merge($genericData, $project);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ $children = $page->children()->map(function ($child) {
|
||||||
'uri' => '/' . $child->uri(),
|
'uri' => '/' . $child->uri(),
|
||||||
'modified' => $child->modified('Y-MM-d'),
|
'modified' => $child->modified('Y-MM-d'),
|
||||||
'status' => $child->status(),
|
'status' => $child->status(),
|
||||||
'logo' => $child->client()->toPage()->logo()->toFile()->url()
|
'logo' => $child->client()->toPage()->logo()->toFile()->url(),
|
||||||
];
|
];
|
||||||
})->values();
|
})->values();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import Tabs from "./Tabs.vue";
|
import Tabs from "./Tabs.vue";
|
||||||
import Project from "./Project.vue";
|
import Project from "./project/Project.vue";
|
||||||
import { useProjectsStore } from "../stores/projects";
|
import { useProjectsStore } from "../stores/projects";
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
|
|
|
||||||
37
src/components/project/ProjectStep.vue
Normal file
37
src/components/project/ProjectStep.vue
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<section
|
||||||
|
class="flex-1"
|
||||||
|
aria-labelledby="votre-brief-label"
|
||||||
|
data-status="done"
|
||||||
|
>
|
||||||
|
<h2 id="votre-brief-label">
|
||||||
|
<span data-icon="votre-brief">Votre brief</span>
|
||||||
|
</h2>
|
||||||
|
<div class="cards | flow">
|
||||||
|
<article class="card">
|
||||||
|
<hgroup class="order-last">
|
||||||
|
<h3 class="card__title | font-serif | text-lg">Votre Brief</h3>
|
||||||
|
</hgroup>
|
||||||
|
<div class="card__meta | flex">
|
||||||
|
<time class="card__date | text-grey-700" datetime="2024-06-12"
|
||||||
|
>12 juin 2024</time
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<figure class="card__images" data-count="13">
|
||||||
|
<img
|
||||||
|
src="http://localhost:8888/media/pages/inspirations/shape-of-the-nature/6ed93d6950-1725442486/d82f18573c439d6edd434ffca62471a7.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="http://localhost:8888/media/pages/inspirations/shape-of-the-nature/7b0fcc5012-1725442486/37a038883c87973036232aa0e43f6da2.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<img
|
||||||
|
src="http://localhost:8888/media/pages/inspirations/shape-of-the-nature/1bbe051c5a-1725442486/0c41d3266e9ce2872f30608cceb28239.png"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
<button class="btn | ml-auto">Demander un RDV</button>
|
<button class="btn | ml-auto">Demander un RDV</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<component :is="stepsComponents[currentStep]" @update:step="changeStep" />
|
<!-- <component :is="stepsComponents[currentStep]" @update:step="changeStep" /> -->
|
||||||
<!-- <VirtualSample /> -->
|
|
||||||
|
|
||||||
<!-- Kanban: Status Brief Enrichi -->
|
<!-- Kanban: Status Brief Enrichi -->
|
||||||
|
|
||||||
<!-- <div class="kanban">
|
<div class="kanban">
|
||||||
<section
|
<ProjectStep v-for="step in steps" :key="step" :step="step" />
|
||||||
|
<!-- <section
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
aria-labelledby="votre-brief-label"
|
aria-labelledby="votre-brief-label"
|
||||||
data-status="done"
|
data-status="done"
|
||||||
|
|
@ -149,8 +149,8 @@
|
||||||
<p>Prochainement disponible</p>
|
<p>Prochainement disponible</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section> -->
|
||||||
</div> -->
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -159,25 +159,35 @@ import { usePageStore } from "../stores/page";
|
||||||
import { useUserStore } from "../stores/user";
|
import { useUserStore } from "../stores/user";
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import Intro from "../components/brief/Intro.vue";
|
import ProjectStep from "../components/project/ProjectStep.vue";
|
||||||
import ModeSelection from "../components/brief/ModeSelection.vue";
|
import Intro from "../components/project/brief/Intro.vue";
|
||||||
import AddImages from "../components/brief/AddImages.vue";
|
import ModeSelection from "../components/project/brief/ModeSelection.vue";
|
||||||
import VirtualSampleVue from "../components/VirtualSample.vue";
|
import AddImages from "../components/project/brief/AddImages.vue";
|
||||||
import VirtualSample from "../components/VirtualSample.vue";
|
|
||||||
|
|
||||||
const { page } = storeToRefs(usePageStore());
|
const { page } = storeToRefs(usePageStore());
|
||||||
const user = useUserStore().user;
|
const user = useUserStore().user;
|
||||||
|
|
||||||
const stepsComponents = {
|
const currentStep = page.value.currentStep;
|
||||||
Intro,
|
const steps = page.value.steps.map((step) => step.value);
|
||||||
ModeSelection,
|
|
||||||
AddImages,
|
|
||||||
};
|
|
||||||
|
|
||||||
const currentStep = ref("Intro");
|
// const stepsComponents = {
|
||||||
|
// Intro,
|
||||||
|
// ModeSelection,
|
||||||
|
// AddImages,
|
||||||
|
// };
|
||||||
|
|
||||||
function changeStep(stepName) {
|
// const currentStep = ref("Intro");
|
||||||
currentStep.value = stepName;
|
|
||||||
|
// function changeStep(stepName) {
|
||||||
|
// currentStep.value = stepName;
|
||||||
|
// }
|
||||||
|
|
||||||
|
function setStepStatus(stepName) {
|
||||||
|
const stepIndex = steps.indexOf(stepName);
|
||||||
|
const currentIndex = steps.indexOf(currentStep.value);
|
||||||
|
if (stepIndex < currentIndex) {
|
||||||
|
return "done";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue