mirror of
https://github.com/Casvt/MIND.git
synced 2026-02-19 11:54:46 -05:00
Refactored notification service UI
This commit is contained in:
@@ -1,15 +1,7 @@
|
||||
.ns-table-container {
|
||||
margin-top: 2rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
#add-service-button {
|
||||
width: min(100%, 17rem);
|
||||
height: 2rem;
|
||||
margin-inline: auto;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -25,129 +17,139 @@
|
||||
transition: transform .125s linear;
|
||||
}
|
||||
|
||||
.ns-table-container:has(#service-list-toggle:checked) #add-service-button > svg {
|
||||
#notification:has(#service-list-toggle:checked) #add-service-button > svg {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.overflow-container {
|
||||
#notification .entries-table {
|
||||
margin-inline: auto;
|
||||
width: min(100%, 50rem);
|
||||
|
||||
overflow-x: auto;
|
||||
--inline-padding: .5rem;
|
||||
}
|
||||
|
||||
.overflow-container > table {
|
||||
border-spacing: 0px;
|
||||
#services-list .empty-row td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overflow-container > table:not(:has(tbody > tr)) {
|
||||
#services-list:has(tr:not(.empty-row)) .empty-row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.overflow-container > table th,
|
||||
.overflow-container > table td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.overflow-container > table th {
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
.overflow-container td {
|
||||
border-top: 1px solid var(--color-gray);
|
||||
padding: .25rem;
|
||||
}
|
||||
|
||||
.title-column {
|
||||
min-width: 9.5rem;
|
||||
width: 25%;
|
||||
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.url-column {
|
||||
min-width: 26rem;
|
||||
width: 65%;
|
||||
width: 26rem;
|
||||
text-wrap-mode: nowrap;
|
||||
}
|
||||
|
||||
.overflow-container table input {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
padding: .25rem;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.overflow-container input:read-only {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.overflow-container .action-column {
|
||||
.action-column {
|
||||
min-width: 4rem;
|
||||
width: 20%;
|
||||
|
||||
display: flex;
|
||||
gap: .5rem;
|
||||
|
||||
padding: calc(.5rem + 2px);
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
.action-column > button {
|
||||
/* */
|
||||
/* Edit and delete windows */
|
||||
/* */
|
||||
#edit-ns-form {
|
||||
width: 100%;
|
||||
height: 10rem;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
|
||||
padding: 1rem;
|
||||
|
||||
& > * {
|
||||
max-width: 24rem;
|
||||
|
||||
&.checked-input-container > input {
|
||||
max-width: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-container .action-column svg {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
#delete-ns-dialog p {
|
||||
padding-inline: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr:has(input:not(:read-only)) button[data-type="save"],
|
||||
tr:has(input:read-only) button[data-type="edit"] {
|
||||
display: flex;
|
||||
}
|
||||
#confirm-delete-ns {
|
||||
min-width: 6rem;
|
||||
width: unset;
|
||||
|
||||
tr:has(input:not(:read-only)) button[data-type="edit"],
|
||||
tr:has(input:read-only) button[data-type="save"] {
|
||||
display: none;
|
||||
padding-inline: 1rem;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* Add service */
|
||||
/* */
|
||||
#add-service-container {
|
||||
margin-top: 1rem;
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.overflow-container:has(#service-list-toggle:checked) table {
|
||||
display: none;
|
||||
#notification:has(#service-list-toggle:checked) {
|
||||
& table {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& #add-service-container {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-container:has(#service-list-toggle:checked) #add-service-container {
|
||||
display: block;
|
||||
#notification:has(#add-service-toggle:checked) {
|
||||
& #service-list,
|
||||
& #ns-search-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& #add-service-window {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.overflow-container:has(#add-service-toggle:checked) #service-list {
|
||||
display: none;
|
||||
}
|
||||
#ns-search-input {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
.overflow-container:has(#add-service-toggle:checked) #add-service-window {
|
||||
display: flex;
|
||||
max-width: 26rem;
|
||||
height: 2rem;
|
||||
|
||||
padding: .25rem .5rem;
|
||||
}
|
||||
|
||||
#service-list {
|
||||
width: min(100%, 48rem);
|
||||
margin-inline: auto;
|
||||
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#service-list p {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#service-list:not(:has(button)) > p,
|
||||
#service-list:has(button:not(.hidden)) > p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#service-list button {
|
||||
width: max(30%, 10rem);
|
||||
width: 12rem;
|
||||
max-width: 15rem;
|
||||
height: 6rem;
|
||||
|
||||
flex-grow: 1;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -155,15 +157,25 @@ tr:has(input:read-only) button[data-type="save"] {
|
||||
padding: .75rem;
|
||||
border-radius: 4px;
|
||||
border: 2px solid var(--color-gray);
|
||||
|
||||
background-color: var(--color-dark);
|
||||
color: var(--color-light);
|
||||
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
|
||||
box-shadow: var(--default-shadow);
|
||||
transition: background-color 150ms ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-gray);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* Add service form */
|
||||
/* */
|
||||
#add-service-window {
|
||||
width: 100%;
|
||||
max-width: 30rem;
|
||||
margin: auto;
|
||||
|
||||
@@ -171,129 +183,121 @@ tr:has(input:read-only) button[data-type="save"] {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#add-service-window .input-style {
|
||||
max-width: 100%;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-mid-gray);
|
||||
}
|
||||
}
|
||||
|
||||
#add-service-window > h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
#add-service-window > p {
|
||||
height: 2.7rem;
|
||||
margin-bottom: calc((1rem + 2px) * -1);
|
||||
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
border: 2px solid var(--color-gray);
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
padding: .75rem 1rem;
|
||||
color: var(--color-gray);
|
||||
padding-inline: .5rem;
|
||||
color: var(--color-mid-gray);
|
||||
|
||||
text-align: left;
|
||||
|
||||
box-shadow: var(--default-shadow);
|
||||
}
|
||||
|
||||
#add-service-window > button {
|
||||
border-radius: 4px;
|
||||
border: 2px solid var(--color-gray);
|
||||
padding: .75rem;
|
||||
}
|
||||
|
||||
#add-service-window > a,
|
||||
#add-service-window > p > a {
|
||||
#add-service-window > a {
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
#add-service-window > div[data-map],
|
||||
#add-service-window > div[data-map] > .entries-list {
|
||||
#add-service-window > div[data-map] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: inherit;
|
||||
}
|
||||
gap: .6rem;
|
||||
|
||||
#add-service-window > div[data-map] {
|
||||
padding: .5rem;
|
||||
border: 2px solid var(--color-gray);
|
||||
border-radius: 4px;
|
||||
box-shadow: var(--default-shadow);
|
||||
}
|
||||
|
||||
#add-service-window > div[data-map] > p {
|
||||
color: var(--color-gray);
|
||||
font-size: 1.1rem;
|
||||
& > p {
|
||||
color: var(--color-mid-gray);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.entries-list {
|
||||
min-height: 5rem;
|
||||
max-height: 15rem;
|
||||
overflow-y: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: .6rem;
|
||||
|
||||
background-color: var(--color-dark);
|
||||
color: var(--color-light);
|
||||
border: 2px solid var(--color-gray);
|
||||
border-radius: 4px;
|
||||
padding: .75rem;
|
||||
padding: .5rem;
|
||||
box-shadow: var(--default-shadow);
|
||||
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.entries-list > p:first-child {
|
||||
color: var(--color-gray);
|
||||
color: var(--color-mid-gray);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.input-entries {
|
||||
width: 100%;
|
||||
max-height: 12rem;
|
||||
width: 100%;
|
||||
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.input-entries:not(:has(div)) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.add-row {
|
||||
width: min(100%, 21rem);
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.add-row input {
|
||||
flex-grow: 1;
|
||||
height: 2rem;
|
||||
min-width: 0rem;
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
.add-row button {
|
||||
width: 6rem;
|
||||
height: 2rem;
|
||||
padding: .35rem .75rem;
|
||||
background-color: var(--color-gray);
|
||||
border-radius: 4px;
|
||||
|
||||
padding: 0rem;
|
||||
}
|
||||
|
||||
.entries-list > button {
|
||||
height: 1.5rem;
|
||||
width: min(100%, 21rem);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
background-color: var(--color-gray);
|
||||
}
|
||||
height: 1.9rem;
|
||||
|
||||
.entries-list > button svg {
|
||||
height: 60%;
|
||||
}
|
||||
& > svg {
|
||||
height: 1rem;
|
||||
|
||||
.entries-list > button path {
|
||||
height: inherit;
|
||||
fill: var(--color-dark);
|
||||
}
|
||||
|
||||
@media (max-width: 543px) {
|
||||
#service-list button {
|
||||
flex-grow: 1;
|
||||
transition: transform 125ms linear;
|
||||
}
|
||||
}
|
||||
|
||||
.entries-list:has(.add-row:not(.hidden)) > button > svg {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
@@ -11,16 +11,22 @@ const constants = {
|
||||
* The amount of time to wait after the user stops typing to automatically
|
||||
* trigger the search
|
||||
*/
|
||||
autoSearchTimeout: 500
|
||||
autoSearchTimeout: 500,
|
||||
|
||||
/**
|
||||
* The amount of time to wait after the user stops typing to automatically
|
||||
* trigger the search for notification services
|
||||
*/
|
||||
autoSearchTimeoutNs: 250
|
||||
}
|
||||
|
||||
const icons = {
|
||||
save: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" style="enable-background:new 0 0 512 512" xml:space="preserve"><g><path d="M12,10a4,4,0,1,0,4,4A4,4,0,0,0,12,10Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,16Z"></path><path d="M22.536,4.122,19.878,1.464A4.966,4.966,0,0,0,16.343,0H5A5.006,5.006,0,0,0,0,5V19a5.006,5.006,0,0,0,5,5H19a5.006,5.006,0,0,0,5-5V7.657A4.966,4.966,0,0,0,22.536,4.122ZM17,2.08V3a3,3,0,0,1-3,3H10A3,3,0,0,1,7,3V2h9.343A2.953,2.953,0,0,1,17,2.08ZM22,19a3,3,0,0,1-3,3H5a3,3,0,0,1-3-3V5A3,3,0,0,1,5,2V3a5.006,5.006,0,0,0,5,5h4a4.991,4.991,0,0,0,4.962-4.624l2.16,2.16A3.02,3.02,0,0,1,22,7.657Z"></path></g></svg>',
|
||||
edit: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" style="enable-background:new 0 0 512 512" xml:space="preserve"><g><g id="_01_align_center" data-name="01 align center"><path d="M22.94,1.06a3.626,3.626,0,0,0-5.124,0L0,18.876V24H5.124L22.94,6.184A3.627,3.627,0,0,0,22.94,1.06ZM4.3,22H2V19.7L15.31,6.4l2.3,2.3ZM21.526,4.77,19.019,7.277l-2.295-2.3L19.23,2.474a1.624,1.624,0,0,1,2.3,2.3Z"></path></g></g></svg>',
|
||||
delete: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" style="enable-background:new 0 0 512 512" xml:space="preserve"><g><g id="_01_align_center" data-name="01 align center"><path d="M22,4H17V2a2,2,0,0,0-2-2H9A2,2,0,0,0,7,2V4H2V6H4V21a3,3,0,0,0,3,3H17a3,3,0,0,0,3-3V6h2ZM9,2h6V4H9Zm9,19a1,1,0,0,1-1,1H7a1,1,0,0,1-1-1V6H18Z"></path><rect x="9" y="10" width="2" height="8"></rect><rect x="13" y="10" width="2" height="8"></rect></g></g></svg>',
|
||||
add: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512" xml:space="preserve"><g><g><path d="M480,224H288V32c0-17.673-14.327-32-32-32s-32,14.327-32,32v192H32c-17.673,0-32,14.327-32,32s14.327,32,32,32h192v192 c0,17.673,14.327,32,32,32s32-14.327,32-32V288h192c17.673,0,32-14.327,32-32S497.673,224,480,224z"></path></g></g></svg>',
|
||||
download: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="512" height="512"><g><path d="M210.731,386.603c24.986,25.002,65.508,25.015,90.51,0.029c0.01-0.01,0.019-0.019,0.029-0.029l68.501-68.501 c7.902-8.739,7.223-22.23-1.516-30.132c-8.137-7.357-20.527-7.344-28.649,0.03l-62.421,62.443l0.149-329.109 C277.333,9.551,267.782,0,256,0l0,0c-11.782,0-21.333,9.551-21.333,21.333l-0.192,328.704L172.395,288 c-8.336-8.33-21.846-8.325-30.176,0.011c-8.33,8.336-8.325,21.846,0.011,30.176L210.731,386.603z"/><path d="M490.667,341.333L490.667,341.333c-11.782,0-21.333,9.551-21.333,21.333V448c0,11.782-9.551,21.333-21.333,21.333H64 c-11.782,0-21.333-9.551-21.333-21.333v-85.333c0-11.782-9.551-21.333-21.333-21.333l0,0C9.551,341.333,0,350.885,0,362.667V448 c0,35.346,28.654,64,64,64h384c35.346,0,64-28.654,64-64v-85.333C512,350.885,502.449,341.333,490.667,341.333z"/></g></svg>',
|
||||
upload: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512.008 512.008" style="enable-background:new 0 0 512.008 512.008;" xml:space="preserve" width="512" height="512"><g><path d="M172.399,117.448l62.421-62.443l-0.149,329.344c0,11.782,9.551,21.333,21.333,21.333l0,0 c11.782,0,21.333-9.551,21.333-21.333l0.149-328.981l62.123,62.144c8.475,8.185,21.98,7.951,30.165-0.524 c7.985-8.267,7.985-21.374,0-29.641L301.273,18.76c-24.986-25.002-65.508-25.015-90.51-0.029c-0.01,0.01-0.019,0.019-0.029,0.029 l-68.501,68.523c-8.185,8.475-7.951,21.98,0.524,30.165C151.024,125.433,164.131,125.433,172.399,117.448z"/><path d="M490.671,341.341L490.671,341.341c-11.782,0-21.333,9.551-21.333,21.333v85.333c0,11.782-9.551,21.333-21.333,21.333h-384 c-11.782,0-21.333-9.551-21.333-21.333v-85.333c0-11.782-9.551-21.333-21.333-21.333l0,0c-11.782,0-21.333,9.551-21.333,21.333 v85.333c0,35.346,28.654,64,64,64h384c35.346,0,64-28.654,64-64v-85.333C512.004,350.892,502.453,341.341,490.671,341.341z"/></g></svg>',
|
||||
save: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve"><g><path d="M12,10a4,4,0,1,0,4,4A4,4,0,0,0,12,10Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,16Z"></path><path d="M22.536,4.122,19.878,1.464A4.966,4.966,0,0,0,16.343,0H5A5.006,5.006,0,0,0,0,5V19a5.006,5.006,0,0,0,5,5H19a5.006,5.006,0,0,0,5-5V7.657A4.966,4.966,0,0,0,22.536,4.122ZM17,2.08V3a3,3,0,0,1-3,3H10A3,3,0,0,1,7,3V2h9.343A2.953,2.953,0,0,1,17,2.08ZM22,19a3,3,0,0,1-3,3H5a3,3,0,0,1-3-3V5A3,3,0,0,1,5,2V3a5.006,5.006,0,0,0,5,5h4a4.991,4.991,0,0,0,4.962-4.624l2.16,2.16A3.02,3.02,0,0,1,22,7.657Z"></path></g></svg>',
|
||||
edit: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve"><g><g id="_01_align_center" data-name="01 align center"><path d="M22.94,1.06a3.626,3.626,0,0,0-5.124,0L0,18.876V24H5.124L22.94,6.184A3.627,3.627,0,0,0,22.94,1.06ZM4.3,22H2V19.7L15.31,6.4l2.3,2.3ZM21.526,4.77,19.019,7.277l-2.295-2.3L19.23,2.474a1.624,1.624,0,0,1,2.3,2.3Z"></path></g></g></svg>',
|
||||
delete: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve"><g><g id="_01_align_center" data-name="01 align center"><path d="M22,4H17V2a2,2,0,0,0-2-2H9A2,2,0,0,0,7,2V4H2V6H4V21a3,3,0,0,0,3,3H17a3,3,0,0,0,3-3V6h2ZM9,2h6V4H9Zm9,19a1,1,0,0,1-1,1H7a1,1,0,0,1-1-1V6H18Z"></path><rect x="9" y="10" width="2" height="8"></rect><rect x="13" y="10" width="2" height="8"></rect></g></g></svg>',
|
||||
add: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 512 512" xml:space="preserve"><g><g><path d="M480,224H288V32c0-17.673-14.327-32-32-32s-32,14.327-32,32v192H32c-17.673,0-32,14.327-32,32s14.327,32,32,32h192v192 c0,17.673,14.327,32,32,32s32-14.327,32-32V288h192c17.673,0,32-14.327,32-32S497.673,224,480,224z"></path></g></g></svg>',
|
||||
download: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512 512" xml:space="preserve" width="512" height="512"><g><path d="M210.731,386.603c24.986,25.002,65.508,25.015,90.51,0.029c0.01-0.01,0.019-0.019,0.029-0.029l68.501-68.501 c7.902-8.739,7.223-22.23-1.516-30.132c-8.137-7.357-20.527-7.344-28.649,0.03l-62.421,62.443l0.149-329.109 C277.333,9.551,267.782,0,256,0l0,0c-11.782,0-21.333,9.551-21.333,21.333l-0.192,328.704L172.395,288 c-8.336-8.33-21.846-8.325-30.176,0.011c-8.33,8.336-8.325,21.846,0.011,30.176L210.731,386.603z"/><path d="M490.667,341.333L490.667,341.333c-11.782,0-21.333,9.551-21.333,21.333V448c0,11.782-9.551,21.333-21.333,21.333H64 c-11.782,0-21.333-9.551-21.333-21.333v-85.333c0-11.782-9.551-21.333-21.333-21.333l0,0C9.551,341.333,0,350.885,0,362.667V448 c0,35.346,28.654,64,64,64h384c35.346,0,64-28.654,64-64v-85.333C512,350.885,502.449,341.333,490.667,341.333z"/></g></svg>',
|
||||
upload: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512.008 512.008" xml:space="preserve" width="512" height="512"><g><path d="M172.399,117.448l62.421-62.443l-0.149,329.344c0,11.782,9.551,21.333,21.333,21.333l0,0 c11.782,0,21.333-9.551,21.333-21.333l0.149-328.981l62.123,62.144c8.475,8.185,21.98,7.951,30.165-0.524 c7.985-8.267,7.985-21.374,0-29.641L301.273,18.76c-24.986-25.002-65.508-25.015-90.51-0.029c-0.01,0.01-0.019,0.019-0.029,0.029 l-68.501,68.523c-8.185,8.475-7.951,21.98,0.524,30.165C151.024,125.433,164.131,125.433,172.399,117.448z"/><path d="M490.671,341.341L490.671,341.341c-11.782,0-21.333,9.551-21.333,21.333v85.333c0,11.782-9.551,21.333-21.333,21.333h-384 c-11.782,0-21.333-9.551-21.333-21.333v-85.333c0-11.782-9.551-21.333-21.333-21.333l0,0c-11.782,0-21.333,9.551-21.333,21.333 v85.333c0,35.346,28.654,64,64,64h384c35.346,0,64-28.654,64-64v-85.333C512.004,350.892,502.453,341.341,490.671,341.341z"/></g></svg>',
|
||||
loading: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m10.5 1.5c0-.828.672-1.5 1.5-1.5s1.5.672 1.5 1.5-.672 1.5-1.5 1.5-1.5-.672-1.5-1.5zm1.5 22.5c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm9-12c0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5-.672-1.5-1.5-1.5-1.5.672-1.5 1.5zm-21 0c0 .828.672 1.5 1.5 1.5s1.5-.672 1.5-1.5-.672-1.5-1.5-1.5-1.5.672-1.5 1.5zm17.293-7.577c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm3.779 3.798c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm-.01 10.567c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm-3.788 3.788c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm-10.577-.01c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm-3.75-3.779c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm-.01-10.596c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5zm3.779-3.769c.828 0 1.5-.672 1.5-1.5s-.672-1.5-1.5-1.5-1.5.672-1.5 1.5.672 1.5 1.5 1.5z"/></svg>'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const NotiEls = {
|
||||
services_list: document.querySelector('#services-list'),
|
||||
search_input: document.querySelector('#ns-search-input'),
|
||||
service_list: document.querySelector('#service-list'),
|
||||
default_service_input: document.querySelector('#default-service-input'),
|
||||
service_selection: document.querySelector('.notification-service-selection'),
|
||||
@@ -8,6 +9,27 @@ const NotiEls = {
|
||||
triggers: {
|
||||
add_service: document.querySelector('#add-service-toggle'),
|
||||
service_list: document.querySelector('#service-list-toggle')
|
||||
},
|
||||
windows: {
|
||||
editService: {
|
||||
dialog: document.querySelector("#edit-ns-dialog"),
|
||||
form: document.querySelector("#edit-ns-form"),
|
||||
close: document.querySelector("#close-edit-ns"),
|
||||
inputContainers: {
|
||||
url: document.querySelector("#edit-ns-form .checked-input-container:has(#edit-ns-url-input)")
|
||||
},
|
||||
inputs: {
|
||||
title: document.querySelector("#edit-ns-title-input"),
|
||||
url: document.querySelector("#edit-ns-url-input")
|
||||
},
|
||||
error: document.querySelector("#edit-ns-url-error")
|
||||
},
|
||||
deleteService: {
|
||||
dialog: document.querySelector("#delete-ns-dialog"),
|
||||
error: document.querySelector("#delete-ns-error"),
|
||||
close: document.querySelector("#close-delete-ns"),
|
||||
confirm: document.querySelector("#confirm-delete-ns")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,33 +37,24 @@ const NotiEls = {
|
||||
// Fill lists and tables
|
||||
//
|
||||
function fillNotificationTable(json) {
|
||||
NotiEls.services_list.innerHTML = '';
|
||||
NotiEls.services_list.querySelectorAll("tr[data-id]").forEach(
|
||||
e => e.remove()
|
||||
)
|
||||
json.result.forEach(service => {
|
||||
const entry = NotiEls.notification_service_row.cloneNode(true);
|
||||
entry.dataset.id = service.id;
|
||||
const entry = NotiEls.notification_service_row.cloneNode(true)
|
||||
entry.dataset.id = service.id
|
||||
|
||||
entry.querySelector('.title-column input').value = service.title;
|
||||
entry.querySelector('.title-column').innerText = service.title
|
||||
entry.querySelector('.url-column').innerText = service.url
|
||||
|
||||
const url_input = entry.querySelector('.url-column input');
|
||||
url_input.value = service.url;
|
||||
url_input.onkeydown = e => {
|
||||
if (e.key === 'Enter')
|
||||
saveService(service.id);
|
||||
};
|
||||
entry.querySelector('button[data-type="edit"]').onclick =
|
||||
e => openEditNotificationService(service.id)
|
||||
|
||||
entry.querySelector('button[data-type="edit"]').onclick = e =>
|
||||
document.querySelectorAll(`tr[data-id="${service.id}"] input`).forEach(
|
||||
e => e.removeAttribute('readonly')
|
||||
);
|
||||
entry.querySelector('button[data-type="delete"]').onclick =
|
||||
e => openDeleteNotificationService(service.id)
|
||||
|
||||
entry.querySelector('button[data-type="save"]').onclick = e =>
|
||||
saveService(service.id);
|
||||
|
||||
entry.querySelector('button[data-type="delete"]').onclick = e =>
|
||||
deleteService(service.id);
|
||||
|
||||
NotiEls.services_list.appendChild(entry);
|
||||
});
|
||||
NotiEls.services_list.appendChild(entry)
|
||||
})
|
||||
};
|
||||
|
||||
function fillNotificationSelection(json) {
|
||||
@@ -58,7 +71,7 @@ function fillNotificationSelection(json) {
|
||||
});
|
||||
|
||||
if (!NotiEls.default_service_input.querySelector(`option[value="${default_service}"]`))
|
||||
setLocalStorage({'default_service':
|
||||
setLocalStorage({'default_service':
|
||||
parseInt(NotiEls.default_service_input.querySelector('option')?.value)
|
||||
|| null
|
||||
});
|
||||
@@ -122,75 +135,83 @@ function fillNotificationServices() {
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
// Actions for table
|
||||
//
|
||||
function saveService(id) {
|
||||
const row = document.querySelector(`tr[data-id="${id}"]`);
|
||||
const save_button = row.querySelector('button[data-type="save"]');
|
||||
function openEditNotificationService(serviceId) {
|
||||
NotiEls.windows.editService.dialog.dataset.id = serviceId;
|
||||
const row = NotiEls.services_list.querySelector(`tr[data-id="${serviceId}"]`);
|
||||
NotiEls.windows.editService.inputs.title.value = row.querySelector('.title-column').innerText;
|
||||
NotiEls.windows.editService.inputs.url.value = row.querySelector('.url-column').innerText;
|
||||
NotiEls.windows.editService.inputContainers.url.classList.remove('error-input-container');
|
||||
NotiEls.windows.editService.dialog.showModal();
|
||||
};
|
||||
|
||||
function editNotificationService() {
|
||||
NotiEls.windows.editService.inputContainers.url.classList.remove('error-input-container')
|
||||
const data = {
|
||||
'title': row.querySelector(`td.title-column > input`).value,
|
||||
'url': row.querySelector(`td.url-column > input`).value
|
||||
};
|
||||
fetch(`${urlPrefix}/api/notificationservices/${id}?api_key=${apiKey}`, {
|
||||
'method': 'PUT',
|
||||
'headers': {'Content-Type': 'application/json'},
|
||||
'body': JSON.stringify(data)
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) return Promise.reject(response.status);
|
||||
title: NotiEls.windows.editService.inputs.title.value,
|
||||
url: NotiEls.windows.editService.inputs.url.value
|
||||
}
|
||||
|
||||
fillNotificationServices();
|
||||
})
|
||||
.catch(e => {
|
||||
if (e === 401)
|
||||
window.location.href = `${urlPrefix}/`;
|
||||
else if (e === 400) {
|
||||
save_button.classList.add('error-icon');
|
||||
save_button.title = 'Invalid Apprise URL';
|
||||
} else
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
|
||||
function deleteService(id, delete_reminders_using=false) {
|
||||
const row = document.querySelector(`tr[data-id="${id}"]`);
|
||||
fetch(`${urlPrefix}/api/notificationservices/${id}?api_key=${apiKey}&delete_reminders_using=${delete_reminders_using}`, {
|
||||
'method': 'DELETE'
|
||||
})
|
||||
.then(response => response.json())
|
||||
const id = parseInt(NotiEls.windows.editService.dialog.dataset.id)
|
||||
sendAPI("PUT", `/notificationservices/${id}`, {}, data)
|
||||
.then(json => {
|
||||
if (json.error !== null) return Promise.reject(json);
|
||||
|
||||
row.remove();
|
||||
fillNotificationServices();
|
||||
if (delete_reminders_using) {
|
||||
fillLibrary(reminderTypes.reminder);
|
||||
fillLibrary(reminderTypes.static_reminder);
|
||||
fillLibrary(reminderTypes.template);
|
||||
};
|
||||
fillNotificationServices()
|
||||
NotiEls.windows.editService.dialog.close()
|
||||
})
|
||||
.catch(e => {
|
||||
if (e.error === 'ApiKeyExpired' || e.error === 'ApiKeyInvalid')
|
||||
window.location.href = `${urlPrefix}/`;
|
||||
e.json().then(json => {
|
||||
if (json.error === "URLInvalid" || json.error === "InvalidKeyValue") {
|
||||
NotiEls.windows.editService.error.innerText = json.result.reason || "Syntax of URL invalid"
|
||||
hide([], [NotiEls.windows.editService.error])
|
||||
NotiEls.windows.editService.inputContainers.url.classList.add('error-input-container')
|
||||
}
|
||||
else
|
||||
console.log(json)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
else if (e.error === 'NotificationServiceInUse') {
|
||||
const delete_reminders = confirm(
|
||||
`The notification service is still in use by a ${e.result.reminder_type.toLowerCase()}. Do you want to delete all ${e.result.reminder_type.toLowerCase()}s that are using the notification service?`
|
||||
);
|
||||
|
||||
if (delete_reminders)
|
||||
deleteService(id, delete_reminders_using=true);
|
||||
return;
|
||||
function openDeleteNotificationService(serviceId) {
|
||||
NotiEls.windows.deleteService.dialog.dataset.id = serviceId
|
||||
NotiEls.windows.deleteService.error.classList.add("hidden")
|
||||
NotiEls.windows.deleteService.confirm.innerText = "Delete"
|
||||
NotiEls.windows.deleteService.confirm.onclick = e => deleteService()
|
||||
NotiEls.windows.deleteService.dialog.showModal()
|
||||
}
|
||||
|
||||
} else
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
function deleteService(delete_reminders_using=false) {
|
||||
const id = parseInt(NotiEls.windows.deleteService.dialog.dataset.id)
|
||||
sendAPI("DELETE", `/notificationservices/${id}`, {delete_reminders_using: delete_reminders_using})
|
||||
.then(json => {
|
||||
NotiEls.windows.deleteService.error.classList.add('hidden')
|
||||
fillNotificationServices()
|
||||
if (delete_reminders_using) {
|
||||
fillLibrary(reminderTypes.reminder)
|
||||
fillLibrary(reminderTypes.static_reminder)
|
||||
fillLibrary(reminderTypes.template)
|
||||
}
|
||||
NotiEls.windows.deleteService.dialog.close()
|
||||
})
|
||||
.catch(e => {
|
||||
e.json().then(json => {
|
||||
if (json.error === 'NotificationServiceInUse') {
|
||||
NotiEls.windows.deleteService.error.innerText =
|
||||
`The notification service is still in use by a ${json.result.reminder_type.toLowerCase()}. Do you want to delete all ${json.result.reminder_type.toLowerCase()}s that are using the notification service?`
|
||||
NotiEls.windows.deleteService.error.classList.remove('hidden')
|
||||
NotiEls.windows.deleteService.confirm.innerText = "Delete Anyway"
|
||||
NotiEls.windows.deleteService.confirm.onclick = e => deleteService(delete_reminders_using=true)
|
||||
}
|
||||
else
|
||||
console.log(json)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Adding a service
|
||||
//
|
||||
//
|
||||
function showServiceList(e) {
|
||||
if (!e.target.checked)
|
||||
return;
|
||||
@@ -208,13 +229,51 @@ function showServiceList(e) {
|
||||
const entry = document.createElement('button');
|
||||
entry.innerText = result.name;
|
||||
entry.onclick = e => showAddServiceWindow(index);
|
||||
entry.style.viewTransitionName = `ns-${index}`;
|
||||
NotiEls.service_list.appendChild(entry);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function searchServiceList() {
|
||||
if (autoSearchTimerNs !== null)
|
||||
clearTimeout(autoSearchTimerNs)
|
||||
|
||||
const f = () => {
|
||||
const query = NotiEls.search_input.value
|
||||
.toLowerCase()
|
||||
.replace('-', '')
|
||||
.replace('_', '')
|
||||
.replace(' ', '');
|
||||
|
||||
if (query === '')
|
||||
NotiEls.service_list.querySelectorAll('button').forEach(
|
||||
e => e.classList.remove('hidden')
|
||||
);
|
||||
|
||||
else
|
||||
NotiEls.service_list.querySelectorAll('button').forEach(
|
||||
e => e.classList.toggle(
|
||||
'hidden',
|
||||
!e.innerText
|
||||
.toLowerCase()
|
||||
.replace('-', '')
|
||||
.replace('_', '')
|
||||
.replace(' ', '')
|
||||
.includes(query)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
if (!document.startViewTransition)
|
||||
f();
|
||||
else
|
||||
document.startViewTransition(f);
|
||||
};
|
||||
|
||||
function createTitle() {
|
||||
const service_title = document.createElement('input');
|
||||
service_title.classList.add('input-style');
|
||||
service_title.id = 'service-title';
|
||||
service_title.type = 'text';
|
||||
service_title.placeholder = 'Service Title';
|
||||
@@ -224,9 +283,13 @@ function createTitle() {
|
||||
|
||||
function createChoice(token) {
|
||||
const choice = document.createElement('select');
|
||||
choice.classList.add('input-style');
|
||||
choice.dataset.map = token.map_to || '';
|
||||
choice.dataset.prefix = '';
|
||||
choice.dataset.default = token.default || '';
|
||||
if (![null, undefined, ''].includes(token.default))
|
||||
choice.dataset.default = token.default
|
||||
else
|
||||
choice.dataset.default = ''
|
||||
choice.placeholder = token.name;
|
||||
choice.required = token.required;
|
||||
token.options.forEach(option => {
|
||||
@@ -235,7 +298,7 @@ function createChoice(token) {
|
||||
entry.innerText = option;
|
||||
choice.appendChild(entry);
|
||||
});
|
||||
if (token.default)
|
||||
if (![null, undefined, ''].includes(token.default))
|
||||
choice.querySelector(`option[value="${token.default}"]`).setAttribute('selected', '');
|
||||
|
||||
return choice;
|
||||
@@ -243,6 +306,7 @@ function createChoice(token) {
|
||||
|
||||
function createString(token) {
|
||||
const str_input = document.createElement('input');
|
||||
str_input.classList.add('input-style');
|
||||
str_input.dataset.map = token.map_to || '';
|
||||
str_input.dataset.prefix = token.prefix || '';
|
||||
str_input.dataset.regex = token.regex || '';
|
||||
@@ -255,9 +319,13 @@ function createString(token) {
|
||||
|
||||
function createInt(token) {
|
||||
const int_input = document.createElement('input');
|
||||
int_input.classList.add('input-style');
|
||||
int_input.dataset.map = token.map_to || '';
|
||||
int_input.dataset.prefix = token.prefix || '';
|
||||
int_input.dataset.default = token.default || '';
|
||||
if (![null, undefined, ''].includes(token.default))
|
||||
int_input.dataset.default = token.default
|
||||
else
|
||||
int_input.dataset.default = ''
|
||||
int_input.type = 'number';
|
||||
int_input.placeholder = `${token.name}${!token.required ? ' (Optional)' : ''}`;
|
||||
int_input.required = token.required;
|
||||
@@ -268,11 +336,35 @@ function createInt(token) {
|
||||
return int_input;
|
||||
};
|
||||
|
||||
function createFloat(token) {
|
||||
const float_input = document.createElement('input');
|
||||
float_input.classList.add('input-style');
|
||||
float_input.dataset.map = token.map_to || '';
|
||||
float_input.dataset.prefix = token.prefix || '';
|
||||
if (![null, undefined, ''].includes(token.default))
|
||||
float_input.dataset.default = token.default
|
||||
else
|
||||
float_input.dataset.default = ''
|
||||
float_input.type = 'number';
|
||||
float_input.step = 0.1;
|
||||
float_input.placeholder = `${token.name}${!token.required ? ' (Optional)' : ''}`;
|
||||
float_input.required = token.required;
|
||||
if (token.min !== null)
|
||||
float_input.min = token.min;
|
||||
if (token.max !== null)
|
||||
float_input.max = token.max;
|
||||
return float_input;
|
||||
};
|
||||
|
||||
function createBool(token) {
|
||||
const bool_input = document.createElement('select');
|
||||
bool_input.classList.add('input-style');
|
||||
bool_input.dataset.map = token.map_to || '';
|
||||
bool_input.dataset.prefix = '';
|
||||
bool_input.dataset.default = token.default || '';
|
||||
if (![null, undefined, ''].includes(token.default))
|
||||
bool_input.dataset.default = token.default
|
||||
else
|
||||
bool_input.dataset.default = ''
|
||||
bool_input.placeholder = token.name;
|
||||
bool_input.required = token.required;
|
||||
[['Yes', 'true'], ['No', 'false']].forEach(option => {
|
||||
@@ -282,7 +374,7 @@ function createBool(token) {
|
||||
bool_input.appendChild(entry);
|
||||
});
|
||||
bool_input.querySelector(`option[value="${token.default}"]`).setAttribute('selected', '');
|
||||
|
||||
|
||||
return bool_input;
|
||||
};
|
||||
|
||||
@@ -304,6 +396,7 @@ function createEntriesList(token) {
|
||||
const add_row = document.createElement('div');
|
||||
add_row.classList.add('add-row', 'hidden');
|
||||
const add_input = document.createElement('input');
|
||||
add_input.classList.add('input-style');
|
||||
add_input.type = 'text';
|
||||
add_input.onkeydown = e => {
|
||||
if (e.key === "Enter") {
|
||||
@@ -314,6 +407,7 @@ function createEntriesList(token) {
|
||||
};
|
||||
add_row.appendChild(add_input);
|
||||
const add_entry_button = document.createElement('button');
|
||||
add_entry_button.classList.add('input-style');
|
||||
add_entry_button.type = 'button';
|
||||
add_entry_button.innerText = 'Add';
|
||||
add_entry_button.onclick = e => addEntry(entries_list);
|
||||
@@ -321,19 +415,22 @@ function createEntriesList(token) {
|
||||
entries_list.appendChild(add_row);
|
||||
|
||||
const add_button = document.createElement('button');
|
||||
add_button.classList.add('input-style');
|
||||
add_button.type = 'button';
|
||||
add_button.innerHTML = icons.add;
|
||||
add_button.onclick = e => toggleAddRow(add_row);
|
||||
entries_list.appendChild(add_button);
|
||||
|
||||
|
||||
return entries_list;
|
||||
};
|
||||
|
||||
function toggleAddRow(row) {
|
||||
if (row.classList.contains('hidden')) {
|
||||
// Show row
|
||||
row.querySelector('input').value = '';
|
||||
const add_input = row.querySelector('input');
|
||||
add_input.value = '';
|
||||
row.classList.remove('hidden');
|
||||
add_input.focus();
|
||||
} else {
|
||||
// Hide row
|
||||
row.classList.add('hidden');
|
||||
@@ -355,7 +452,7 @@ function showAddServiceWindow(index) {
|
||||
|
||||
const data = notification_services[index];
|
||||
console.log(data);
|
||||
|
||||
|
||||
const title = document.createElement('h3');
|
||||
title.innerText = data.name;
|
||||
window.appendChild(title);
|
||||
@@ -366,12 +463,13 @@ function showAddServiceWindow(index) {
|
||||
docs.innerText = 'Documentation';
|
||||
window.appendChild(docs);
|
||||
|
||||
window.appendChild(createTitle());
|
||||
|
||||
window.appendChild(createTitle());
|
||||
|
||||
[[data.details.tokens, 'tokens'], [data.details.args, 'args']].forEach(vars => {
|
||||
if (vars[1] === 'args' && vars[0].length > 0) {
|
||||
// The args are hidden behind a "Show Advanced Settings" button
|
||||
const show_args = document.createElement('button');
|
||||
show_args.classList.add('input-style');
|
||||
show_args.type = 'button';
|
||||
show_args.innerText = 'Show Advanced Settings';
|
||||
show_args.onclick = e => {
|
||||
@@ -389,29 +487,31 @@ function showAddServiceWindow(index) {
|
||||
desc.dataset.is_arg = vars[1] === 'args';
|
||||
window.appendChild(desc);
|
||||
result = createChoice(token);
|
||||
|
||||
|
||||
} else if (token.type === 'list') {
|
||||
const joint_list = document.createElement('div');
|
||||
joint_list.dataset.map = token.map_to;
|
||||
joint_list.dataset.delim = token.delim;
|
||||
|
||||
|
||||
const desc = document.createElement('p');
|
||||
desc.innerText = `${token.name}${!token.required ? ' (Optional)' : ''}`;
|
||||
joint_list.appendChild(desc);
|
||||
|
||||
|
||||
if (token.content.length === 0)
|
||||
joint_list.appendChild(createEntriesList(token));
|
||||
else
|
||||
token.content.forEach(content =>
|
||||
joint_list.appendChild(createEntriesList(content))
|
||||
);
|
||||
|
||||
|
||||
result = joint_list;
|
||||
|
||||
|
||||
} else if (token.type === 'string')
|
||||
result = createString(token);
|
||||
else if (token.type === 'int')
|
||||
result = createInt(token);
|
||||
else if (token.type === 'float')
|
||||
result = createFloat(token);
|
||||
else if (token.type === 'bool') {
|
||||
const desc = document.createElement('p');
|
||||
desc.innerText = `${token.name}${!token.required ? ' (Optional)' : ''}`;
|
||||
@@ -423,24 +523,26 @@ function showAddServiceWindow(index) {
|
||||
result.dataset.is_arg = vars[1] === 'args';
|
||||
window.appendChild(result);
|
||||
});
|
||||
|
||||
|
||||
if (vars[1] === 'args' && vars[0].length > 0)
|
||||
window.querySelectorAll('[data-is_arg="true"]').forEach(
|
||||
el => el.classList.toggle('hidden')
|
||||
);
|
||||
})
|
||||
|
||||
|
||||
// Bottom options
|
||||
const options = document.createElement('div');
|
||||
options.classList.add('options');
|
||||
|
||||
const cancel = document.createElement('button');
|
||||
cancel.classList.add('input-style');
|
||||
cancel.type = 'button';
|
||||
cancel.innerText = 'Cancel';
|
||||
cancel.onclick = e => NotiEls.triggers.add_service.checked = false;
|
||||
options.appendChild(cancel);
|
||||
|
||||
const test = document.createElement('button');
|
||||
test.classList.add('input-style');
|
||||
test.id = 'test-service';
|
||||
test.type = 'button';
|
||||
test.onclick = e => testService();
|
||||
@@ -453,6 +555,7 @@ function showAddServiceWindow(index) {
|
||||
test.appendChild(test_sent_text);
|
||||
|
||||
const add = document.createElement('button');
|
||||
add.classList.add('input-style');
|
||||
add.type = 'submit';
|
||||
add.innerText = 'Add';
|
||||
options.appendChild(add);
|
||||
@@ -476,7 +579,7 @@ function buildAppriseURL() {
|
||||
} else if (i.nodeName === 'DIV') {
|
||||
let value =
|
||||
[...i.querySelectorAll('.entries-list')]
|
||||
.map(l =>
|
||||
.map(l =>
|
||||
[...l.querySelectorAll('.input-entries > div')]
|
||||
.map(e => `${l.dataset.prefix || ''}${e.innerText}`)
|
||||
)
|
||||
@@ -493,7 +596,7 @@ function buildAppriseURL() {
|
||||
const matching_templates = data.details.templates.filter(template =>
|
||||
input_keys === template.replaceAll('}', '{').split('{').filter((e, i) => i % 2).sort().join()
|
||||
);
|
||||
|
||||
|
||||
if (!matching_templates.length)
|
||||
return null;
|
||||
|
||||
@@ -509,9 +612,9 @@ function buildAppriseURL() {
|
||||
if (['INPUT', 'SELECT'].includes(el.nodeName) && el.value && el.value !== el.dataset.default)
|
||||
return `${el.dataset.map}=${el.value}`;
|
||||
else if (el.nodeName == 'DIV') {
|
||||
let value =
|
||||
let value =
|
||||
[...el.querySelectorAll('.entries-list')]
|
||||
.map(l =>
|
||||
.map(l =>
|
||||
[...l.querySelectorAll('.input-entries > div')]
|
||||
.map(e => `${l.dataset.prefix || ''}${e.innerText}`)
|
||||
)
|
||||
@@ -575,7 +678,7 @@ function testService() {
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) return Promise.reject(response.status);
|
||||
|
||||
|
||||
test_button.classList.remove('error-input');
|
||||
test_button.title = '';
|
||||
test_button.classList.add('show-sent');
|
||||
@@ -593,14 +696,14 @@ function testService() {
|
||||
|
||||
function addService() {
|
||||
const add_button = NotiEls.add_service_window.querySelector('.options > button[type="submit"]');
|
||||
|
||||
|
||||
// Check regexes for input's
|
||||
[...NotiEls.add_service_window.querySelectorAll('input:not([data-regex=""])[data-regex]')]
|
||||
.forEach(el => el.classList.remove('error-input'));
|
||||
|
||||
const faulty_inputs =
|
||||
[...NotiEls.add_service_window.querySelectorAll('input:not([data-regex=""])[data-regex]')]
|
||||
.filter(el =>
|
||||
.filter(el =>
|
||||
!(
|
||||
(!el.required && el.value === '')
|
||||
||
|
||||
@@ -631,7 +734,7 @@ function addService() {
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) return Promise.reject(response.status);
|
||||
|
||||
|
||||
add_button.classList.remove('error-input');
|
||||
add_button.title = '';
|
||||
|
||||
@@ -657,4 +760,29 @@ fillNotificationServices();
|
||||
let notification_services = null;
|
||||
|
||||
NotiEls.triggers.service_list.onchange = showServiceList;
|
||||
NotiEls.add_service_window.action = 'javascript:addService();';
|
||||
NotiEls.add_service_window.action = 'javascript:addService();';
|
||||
|
||||
NotiEls.windows.editService.dialog.onclick = e => {
|
||||
if (e.target === e.currentTarget) {
|
||||
e.stopPropagation()
|
||||
NotiEls.windows.editService.dialog.close();
|
||||
}
|
||||
}
|
||||
NotiEls.windows.editService.form.action = 'javascript:editNotificationService()'
|
||||
NotiEls.windows.editService.close.onclick = e => NotiEls.windows.editService.dialog.close();
|
||||
|
||||
NotiEls.windows.deleteService.dialog.onclick = e => {
|
||||
if (e.target === e.currentTarget) {
|
||||
e.stopPropagation()
|
||||
NotiEls.windows.deleteService.dialog.close()
|
||||
}
|
||||
}
|
||||
NotiEls.windows.deleteService.close.onclick = e => NotiEls.windows.deleteService.dialog.close()
|
||||
|
||||
var autoSearchTimerNs = null
|
||||
NotiEls.search_input.oninput = e => {
|
||||
if (autoSearchTimerNs !== null)
|
||||
clearTimeout(autoSearchTimerNs)
|
||||
|
||||
autoSearchTimerNs = setTimeout(searchServiceList, constants.autoSearchTimeoutNs)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,21 @@ function showWindow(id) {
|
||||
constants.windowAnimationDuration
|
||||
)
|
||||
|
||||
document.body.onkeydown = null
|
||||
if (id === "notification") {
|
||||
document.body.onkeydown = e => {
|
||||
if (
|
||||
e.key === '/'
|
||||
&& NotiEls.triggers.service_list.checked
|
||||
&& !NotiEls.triggers.add_service.checked
|
||||
&& document.activeElement !== NotiEls.search_input
|
||||
) {
|
||||
NotiEls.search_input.focus()
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
document.body.onkeydown = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,12 +38,8 @@
|
||||
<table>
|
||||
<tbody>
|
||||
<tr class="notification-service-row" data-id="">
|
||||
<td class="title-column">
|
||||
<input type="text" readonly>
|
||||
</td>
|
||||
<td class="url-column">
|
||||
<input type="text" readonly>
|
||||
</td>
|
||||
<td class="title-column"></td>
|
||||
<td class="url-column"></td>
|
||||
<td class="action-column">
|
||||
<button data-type="edit" title="Edit">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve">
|
||||
@@ -54,14 +50,6 @@
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<button data-type="save" title="Save Edits">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M12,10a4,4,0,1,0,4,4A4,4,0,0,0,12,10Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,12,16Z"></path>
|
||||
<path d="M22.536,4.122,19.878,1.464A4.966,4.966,0,0,0,16.343,0H5A5.006,5.006,0,0,0,0,5V19a5.006,5.006,0,0,0,5,5H19a5.006,5.006,0,0,0,5-5V7.657A4.966,4.966,0,0,0,22.536,4.122ZM17,2.08V3a3,3,0,0,1-3,3H10A3,3,0,0,1,7,3V2h9.343A2.953,2.953,0,0,1,17,2.08ZM22,19a3,3,0,0,1-3,3H5a3,3,0,0,1-3-3V5A3,3,0,0,1,5,2V3a5.006,5.006,0,0,0,5,5h4a4.991,4.991,0,0,0,4.962-4.624l2.16,2.16A3.02,3.02,0,0,1,22,7.657Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<button data-type="delete" title="Delete">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" xml:space="preserve">
|
||||
<g>
|
||||
@@ -91,6 +79,41 @@
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="edit-ns-dialog">
|
||||
<div class="dialog-container">
|
||||
<div class="dialog-header">
|
||||
<h2>Edit Notification Service</h2>
|
||||
</div>
|
||||
<div class="dialog-content">
|
||||
<form id="edit-ns-form">
|
||||
<input type="text" id="edit-ns-title-input" placeholder="Title" class="input-style" required>
|
||||
|
||||
<div class="checked-input-container">
|
||||
<input type="text" id="edit-ns-url-input" placeholder="Apprise URL" class="input-style" required>
|
||||
<p id="edit-ns-url-error">Invalid URL</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="dialog-footer">
|
||||
<button id="close-edit-ns" class="input-style">Cancel</button>
|
||||
<button type="submit" form="edit-ns-form" class="input-style">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="delete-ns-dialog">
|
||||
<div class="dialog-container">
|
||||
<div class="dialog-content">
|
||||
<p>Are you sure you want to permanently delete this notification service?</p>
|
||||
<p class="error hidden" id="delete-ns-error">Failed to delete notification service</p>
|
||||
<div class="confirm-container">
|
||||
<button id="confirm-delete-ns" class="input-style">Delete</button>
|
||||
<button id="close-delete-ns" class="input-style">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<header>
|
||||
<div>
|
||||
<label for="nav-toggle" id="toggle-nav">
|
||||
@@ -341,47 +364,39 @@
|
||||
|
||||
<div id="notification">
|
||||
<h2>Notification Services</h2>
|
||||
<p>Setup your notification providers here</p>
|
||||
<div class="ns-table-container">
|
||||
<label
|
||||
id="add-service-button"
|
||||
title="Toggle adding notification service"
|
||||
for="service-list-toggle"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512" xml:space="preserve">
|
||||
<label id="add-service-button" for="service-list-toggle" title="Toggle adding notification service">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M480,224H288V32c0-17.673-14.327-32-32-32s-32,14.327-32,32v192H32c-17.673,0-32,14.327-32,32s14.327,32,32,32h192v192 c0,17.673,14.327,32,32,32s32-14.327,32-32V288h192c17.673,0,32-14.327,32-32S497.673,224,480,224z"></path>
|
||||
</g>
|
||||
<path d="M480,224H288V32c0-17.673-14.327-32-32-32s-32,14.327-32,32v192H32c-17.673,0-32,14.327-32,32s14.327,32,32,32h192v192 c0,17.673,14.327,32,32,32s32-14.327,32-32V288h192c17.673,0,32-14.327,32-32S497.673,224,480,224z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</label>
|
||||
<div class="overflow-container">
|
||||
<input type="checkbox" id="service-list-toggle" class="hidden">
|
||||
<input type="checkbox" id="add-service-toggle" class="hidden">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title-column">Title</th>
|
||||
<th class="url-column">Apprise URL</th>
|
||||
<th title="Actions" aria-label="Actions" class="action-column">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="256" height="256" x="0" y="0" viewBox="0 0 24 24" style="enable-background:new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<path d="M11.24,24a2.262,2.262,0,0,1-.948-.212,2.18,2.18,0,0,1-1.2-2.622L10.653,16H6.975A3,3,0,0,1,4.1,12.131l3.024-10A2.983,2.983,0,0,1,10,0h3.693a2.6,2.6,0,0,1,2.433,3.511L14.443,8H17a3,3,0,0,1,2.483,4.684l-6.4,10.3A2.2,2.2,0,0,1,11.24,24ZM10,2a1,1,0,0,0-.958.71l-3.024,10A1,1,0,0,0,6.975,14H12a1,1,0,0,1,.957,1.29L11.01,21.732a.183.183,0,0,0,.121.241A.188.188,0,0,0,11.4,21.9l6.4-10.3a1,1,0,0,0,.078-1.063A.979.979,0,0,0,17,10H13a1,1,0,0,1-.937-1.351l2.19-5.84A.6.6,0,0,0,13.693,2Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="services-list">
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="add-service-container">
|
||||
<div id="service-list">
|
||||
</div>
|
||||
<form id="add-service-window"></form>
|
||||
</div>
|
||||
</g>
|
||||
</svg>
|
||||
</label>
|
||||
<input type="checkbox" id="service-list-toggle" class="hidden">
|
||||
<input type="checkbox" id="add-service-toggle" class="hidden">
|
||||
<div class="table-container">
|
||||
<table class="entries-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title-column">Title</th>
|
||||
<th class="url-column">Apprise URL</th>
|
||||
<th title="Actions">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="services-list">
|
||||
<tr class="empty-row">
|
||||
<td colspan="3">No Services</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="add-service-container">
|
||||
<input type="text" id="ns-search-input" class="input-style" placeholder="Type '/' to search services...">
|
||||
<div id="service-list">
|
||||
<p>No Results</p>
|
||||
</div>
|
||||
<form id="add-service-window"></form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user