186 lines
5.9 KiB
Plaintext
186 lines
5.9 KiB
Plaintext
package component
|
|
|
|
import (
|
|
"forge.cadoles.com/wpetit/clearcase/internal/core/model"
|
|
"forge.cadoles.com/wpetit/clearcase/internal/http/form"
|
|
common "forge.cadoles.com/wpetit/clearcase/internal/http/handler/webui/common/component"
|
|
)
|
|
|
|
type IssuePageVModel struct {
|
|
IssueURL string
|
|
SummaryForm *form.Form
|
|
IssueForm *form.Form
|
|
Projects []*model.Project
|
|
SelectedProjectID string
|
|
}
|
|
|
|
func NewIssueSummaryForm() *form.Form {
|
|
return form.New(
|
|
form.NewField(
|
|
"project",
|
|
form.Attrs{},
|
|
form.NonEmpty("Ce champs ne doit pas être vide."),
|
|
),
|
|
form.NewField(
|
|
"summary",
|
|
form.Attrs{
|
|
"type": "textarea",
|
|
"rows": "20",
|
|
"placeholder": "Décrivez rapidement le sujet du problème rencontré ou de l'évolution souhaitée...",
|
|
},
|
|
form.NonEmpty("Ce champs ne doit pas être vide."),
|
|
),
|
|
)
|
|
}
|
|
|
|
func NewIssueForm() *form.Form {
|
|
return form.New(
|
|
form.NewField(
|
|
"title",
|
|
form.Attrs{
|
|
"type": "text",
|
|
},
|
|
form.NonEmpty("Ce champs ne doit pas être vide."),
|
|
),
|
|
form.NewField(
|
|
"body",
|
|
form.Attrs{
|
|
"type": "textarea",
|
|
"rows": "20",
|
|
},
|
|
form.NonEmpty("Ce champs ne doit pas être vide."),
|
|
),
|
|
)
|
|
}
|
|
|
|
templ IssuePage(vmodel IssuePageVModel) {
|
|
@common.Page(common.WithTitle("Nouvelle demande")) {
|
|
<div class="container is-fluid">
|
|
<section class="section">
|
|
<div class="buttons is-right">
|
|
<a class="button is-medium" href={ common.BaseURL(ctx, common.WithPath("/auth/logout")) }>Se déconnecter</a>
|
|
</div>
|
|
if vmodel.IssueURL != "" {
|
|
<article class="message is-primary">
|
|
<div class="message-header">
|
|
<p>Demande créée !</p>
|
|
<button class="delete" aria-label="delete" hx-on:click="onCloseMessage(this)"></button>
|
|
</div>
|
|
<div class="message-body">
|
|
Votre demande a été créée et est disponible à l'adresse suivante:
|
|
<a href={ templ.SafeURL(vmodel.IssueURL) } target="_blank"><code>{ vmodel.IssueURL }</code></a>.
|
|
</div>
|
|
</article>
|
|
<script type="text/javascript">
|
|
function clearSummary(projectId) {
|
|
sessionStorage.removeItem(`summary-${projectId}`)
|
|
}
|
|
function openIssue(issueUrl) {
|
|
window.open(issueUrl, "_blank");
|
|
}
|
|
</script>
|
|
@templ.JSFuncCall("clearSummary", vmodel.SelectedProjectID)
|
|
@templ.JSFuncCall("openIssue", vmodel.IssueURL)
|
|
}
|
|
<div class="columns">
|
|
<div class="column is-4">
|
|
<form id="summary-form" action={ common.CurrentURL(ctx) } method="put" hx-disabled-elt="textarea, input, select, button" hx-on:htmx:before-send="savePreferredProject()" hx-indicator="#generation-progress">
|
|
<h2 class="title is-size-2">Résumé de la demande</h2>
|
|
@common.FormSelect(
|
|
vmodel.SummaryForm, "issue-project", "project", "Projet",
|
|
common.WithOptions(projectsToOptions(vmodel.Projects)...),
|
|
common.WithAttrs(
|
|
"hx-get", string(common.CurrentURL(ctx, common.WithoutValues("project", "*"))),
|
|
"hx-target", "body",
|
|
"hx-push-url", "true",
|
|
),
|
|
)
|
|
@common.FormTextarea(
|
|
vmodel.SummaryForm, "issue-summary", "summary", "Résumé",
|
|
common.WithTextareaAttrs(
|
|
"hx-on:change", "onSummaryChange(event)",
|
|
),
|
|
)
|
|
<div class="buttons is-right">
|
|
<button type="submit" class="button is-primary is-large">
|
|
<span class="icon">
|
|
<i class="fa fa-robot"></i>
|
|
</span>
|
|
<span>Générer le ticket</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="column">
|
|
<h2 class="title is-size-2">Votre demande</h2>
|
|
<form action={ common.CurrentURL(ctx) } method="post" hx-disabled-elt="textarea, input, select, button" hx-indicator="#generation-progress">
|
|
@common.FormField(vmodel.IssueForm, "issue-title", "title", "Titre")
|
|
@common.FormTextarea(vmodel.IssueForm, "issue-body", "body", "Corps")
|
|
<div class="buttons is-right">
|
|
<button type="submit" class="button is-primary is-large">
|
|
<span class="icon">
|
|
<i class="fa fa-rocket"></i>
|
|
</span>
|
|
<span>Créer le ticket</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<progress id="generation-progress" class="htmx-indicator progress"></progress>
|
|
</section>
|
|
</div>
|
|
<script type="text/javascript">
|
|
function onCloseMessage(closeElement) {
|
|
closeElement.closest('.message').style.display = 'none';
|
|
}
|
|
|
|
function onSummaryChange(evt) {
|
|
const summary = evt.currentTarget.value;
|
|
const projectId = document.getElementById("issue-project").value;
|
|
sessionStorage.setItem(`summary-${projectId}`, summary);
|
|
}
|
|
|
|
function savePreferredProject() {
|
|
const projectId = document.getElementById("issue-project").value;
|
|
localStorage.setItem(`preferred-project`, projectId);
|
|
}
|
|
|
|
function restorePreferredProject() {
|
|
const preferredProject = localStorage.getItem(`preferred-project`);
|
|
if (!preferredProject) return;
|
|
const projectElement = document.getElementById("issue-project");
|
|
if (!projectElement) return;
|
|
if (preferredProject === projectElement.value) return;
|
|
projectElement.value = preferredProject;
|
|
projectElement.dispatchEvent(new Event('change'));
|
|
}
|
|
|
|
function restoreLastSummary() {
|
|
const summaryTextarea = document.getElementById("issue-summary");
|
|
if (!summaryTextarea) return;
|
|
const summary = summaryTextarea.value;
|
|
if (summary !== "") return;
|
|
const projectId = document.getElementById("issue-project").value;
|
|
if (!projectId) return;
|
|
const savedSummary = sessionStorage.getItem(`summary-${projectId}`);
|
|
if (!savedSummary) return;
|
|
summaryTextarea.value = savedSummary;
|
|
}
|
|
|
|
htmx.onLoad(function(){
|
|
restoreLastSummary();
|
|
restorePreferredProject();
|
|
})
|
|
</script>
|
|
}
|
|
}
|
|
|
|
func projectsToOptions(projects []*model.Project) []string {
|
|
options := make([]string, 0, len(projects)*2)
|
|
for _, p := range projects {
|
|
options = append(options, p.Name, p.ID)
|
|
}
|
|
return options
|
|
}
|