2024-08-25 00:51:16 +00:00
< template >
2024-08-26 04:15:22 +00:00
< Dialog
title = "Edit summary template"
: confirm - close = "hasChanged"
>
2024-08-25 00:51:16 +00:00
< div class = "dialog-body" >
2024-08-26 04:15:22 +00:00
< ul class = "templates nolist" >
< li
v - for = "storedTemplate in templates"
: key = "`template-${storedTemplate.id}`"
class = "template-key"
: class = "{ selected: selectedTemplate === storedTemplate.id }"
@ click = "selectTemplate(storedTemplate.id)"
> { { storedTemplate . name } } < / li >
< li
class = "template-key add"
@ click = "add"
>
< Icon
icon = "plus3"
/ >
< / li >
< / ul >
2024-08-25 00:51:16 +00:00
< textarea
2024-08-26 04:15:22 +00:00
ref = "input"
2024-08-25 00:51:16 +00:00
v - model = "template"
height = "3"
class = "input edit"
@ input = "update"
/ >
< textarea
: value = "summary"
class = "input summary"
: class = "{ error: hasError }"
wrap = "soft"
@ click = "$event.target.select()"
/ >
< div class = "dialog-actions" >
< div class = "actions" >
< button
class = "button"
@ click = "copy"
> Copy < / button >
< button
class = "button"
@ click = "reset"
2024-08-26 04:15:22 +00:00
> Default < / button >
2024-08-25 00:51:16 +00:00
< / div >
2024-08-26 04:15:22 +00:00
< form
class = "actions save"
@ submit . prevent = "save"
>
< Icon
v - if = "selectedTemplate"
icon = "bin"
class = "remove"
@ click = "remove"
/ >
2024-08-25 00:51:16 +00:00
< input
2024-08-26 04:15:22 +00:00
v - model = "templateName"
2024-08-25 00:51:16 +00:00
class = "input"
placeholder = "Name"
2024-08-26 04:15:22 +00:00
required
2024-08-25 00:51:16 +00:00
>
< button
class = "button"
> Save < / button >
2024-08-26 04:15:22 +00:00
< / form >
2024-08-25 00:51:16 +00:00
< / div >
< / div >
< / Dialog >
< / template >
< script setup >
2024-08-26 04:15:22 +00:00
import { ref , inject } from 'vue' ;
2024-08-25 00:51:16 +00:00
import { parse } from 'yaml' ;
import Cookies from 'js-cookie' ;
2024-08-26 04:15:22 +00:00
// import slugify from '#/utils/slugify.js';
2024-08-25 00:51:16 +00:00
import events from '#/src/events.js' ;
2024-08-26 04:15:22 +00:00
import { get , post , del } from '#/src/api.js' ;
2024-08-25 00:51:16 +00:00
import processSummaryTemplate from '#/utils/process-summary-template.js' ;
import Dialog from '#/components/dialog/dialog.vue' ;
import defaultTemplate from '#/assets/summary.yaml?raw' ; // eslint-disable-line import/no-unresolved
2024-08-26 04:15:22 +00:00
const emit = defineEmits ( [ 'event' ] ) ;
const pageContext = inject ( 'pageContext' ) ;
2024-08-25 00:51:16 +00:00
const cookies = Cookies . withConverter ( {
write : ( value ) => value ,
} ) ;
const props = defineProps ( {
release : {
type : Object ,
default : null ,
} ,
2024-08-26 04:15:22 +00:00
selected : {
type : Number ,
default : null ,
} ,
2024-08-25 00:51:16 +00:00
} ) ;
2024-08-26 04:15:22 +00:00
const templates = ref ( pageContext . assets . templates ) ;
const selectedTemplate = ref ( props . selected || templates . value . at ( 0 ) ? . id || null ) ;
const initialTemplate = templates . value . find ( ( storedTemplate ) => storedTemplate . id === selectedTemplate . value ) || null ;
const template = ref ( initialTemplate ? . template || defaultTemplate ) ;
2024-08-25 00:51:16 +00:00
const hasError = ref ( false ) ;
2024-08-26 04:15:22 +00:00
const hasChanged = ref ( false ) ;
const input = ref ( null ) ;
const templateName = ref ( initialTemplate ? . name || ` custom_ ${ Date . now ( ) } ` ) ;
2024-08-25 00:51:16 +00:00
function getSummary ( ) {
2024-08-26 04:15:22 +00:00
return processSummaryTemplate ( template . value , props . release ) ;
2024-08-25 00:51:16 +00:00
}
const summary = ref ( getSummary ( ) ) ;
2024-08-26 04:15:22 +00:00
function selectTemplate ( templateId ) {
selectedTemplate . value = templateId ;
const nextTemplate = templates . value . find ( ( storedTemplate ) => storedTemplate . id === templateId ) ;
template . value = nextTemplate . template ;
templateName . value = nextTemplate . name ;
summary . value = getSummary ( ) ;
emit ( 'event' , {
type : 'select' ,
data : templateId ,
} ) ;
cookies . set ( 'selectedTemplate' , String ( templateId ) ) ;
}
2024-08-25 00:51:16 +00:00
function update ( ) {
hasError . value = false ;
2024-08-26 04:15:22 +00:00
hasChanged . value = true ;
2024-08-25 00:51:16 +00:00
try {
summary . value = getSummary ( ) ;
} catch ( error ) {
hasError . value = true ;
}
}
2024-08-26 04:15:22 +00:00
async function save ( ) {
2024-08-25 00:51:16 +00:00
try {
parse ( template . value ) ;
2024-08-26 04:15:22 +00:00
hasChanged . value = false ;
2024-08-25 00:51:16 +00:00
2024-08-26 04:15:22 +00:00
const createdTemplate = await post ( '/templates' , {
name : templateName . value ,
template : template . value ,
successFeedback : ` Saved summary template ' ${ templateName . value } ' ` ,
errorFeedback : ` Failed to save summary template ' ${ templateName . value } ' ` ,
2024-08-25 00:51:16 +00:00
} ) ;
2024-08-26 04:15:22 +00:00
templates . value = await get ( ` /users/ ${ pageContext . user . id } /templates ` ) ;
selectTemplate ( createdTemplate . id ) ;
2024-08-25 00:51:16 +00:00
} catch ( error ) {
events . emit ( 'feedback' , {
type : 'error' ,
2024-08-26 04:15:22 +00:00
message : ` Failed to save summary template ' ${ templateName . value } ': ${ error . message } ` ,
} ) ;
}
}
function add ( ) {
selectedTemplate . value = null ;
template . value = '' ;
templateName . value = ` custom_ ${ Date . now ( ) } ` ;
summary . value = '' ;
input . value . focus ( ) ;
}
async function remove ( ) {
if ( confirm ( ` Are you sure you want to delete summary template ${ templateName . value } ? ` ) ) { // eslint-disable-line no-restricted-globals, no-alert
await del ( ` /templates/ ${ selectedTemplate . value } ` , {
undoFeedback : ` Deleted summary template ' ${ templateName . value } ' ` ,
errorFeedback : ` Failed to remove summary template ' ${ templateName . value } ' ` ,
2024-08-25 00:51:16 +00:00
} ) ;
2024-08-26 04:15:22 +00:00
templates . value = await get ( ` /users/ ${ pageContext . user . id } /templates ` ) ;
selectTemplate ( templates . value . at ( - 1 ) ? . id ) ;
2024-08-25 00:51:16 +00:00
}
}
function copy ( ) {
navigator . clipboard . writeText ( summary . value ) ;
events . emit ( 'feedback' , {
type : 'success' ,
message : 'Summary copied to clipboard' ,
} ) ;
}
function reset ( ) {
2024-08-26 04:15:22 +00:00
if ( confirm ( 'Are you sure you want to reset the summary template to the default? Your custom template will be discarded.' ) ) { // eslint-disable-line no-restricted-globals, no-alert
2024-08-25 00:51:16 +00:00
template . value = defaultTemplate ;
update ( ) ;
events . emit ( 'feedback' , {
type : 'undo' ,
message : 'Reset summary template' ,
} ) ;
}
}
< / script >
< style scoped >
: deep ( . dialog - container . dialog ) {
background : red ;
}
. dialog - body {
display : flex ;
width : 50 rem ;
max - width : 100 % ;
height : 100 vh ;
}
. input {
resize : none ;
}
. edit {
flex - grow : 1 ;
}
. summary {
min - height : 4 rem ;
flex - shrink : 0 ;
line - height : 1.5 ;
& . error {
background : var ( -- background - error ) ;
}
}
. dialog - actions {
display : flex ;
justify - content : space - between ; ;
gap : 1 rem ;
padding : 1 rem ;
. input {
flex - grow : 1 ;
width : 0 ;
max - width : 10 rem ;
}
}
. actions {
display : flex ;
2024-08-26 04:15:22 +00:00
. button : not ( : last - child ) {
margin - right : 1 rem ;
}
2024-08-25 00:51:16 +00:00
& . save {
flex - grow : 1 ;
justify - content : flex - end ;
2024-08-26 04:15:22 +00:00
. input {
margin - right : 1 rem ;
}
}
. icon {
height : 100 % ;
padding : 0 1 rem ;
cursor : pointer ;
fill : var ( -- glass ) ;
& . remove : hover {
fill : var ( -- error ) ;
}
}
}
. templates {
display : flex ;
align - items : center ;
padding : .5 rem ;
overflow - x : auto ;
}
. template - key {
padding : .25 rem .5 rem ;
border - radius : .25 rem ;
cursor : pointer ;
. icon {
fill : var ( -- glass ) ;
}
& . selected {
background : var ( -- primary ) ;
color : var ( -- text - light ) ;
}
& : hover : not ( . selected ) {
color : var ( -- primary ) ;
. icon {
fill : var ( -- primary ) ;
}
2024-08-25 00:51:16 +00:00
}
}
< / style >