{% extends 'base.html' %} {% load i18n %} {% block body %}

{% trans "Management for:" %} {{ key }}

{% trans "Getting Started" %}
  1. {% blocktrans %} Here is where you can store your Apprise configuration associated with the key {{key}}. {% endblocktrans %}
  2. {% blocktrans %} You can always refer to the Apprise Wiki if you're having troubles assembling your URL(s). {% endblocktrans %}
  3. {% blocktrans %} In the future you can return to this configuration screen at any time by placing the following into your browser: {% endblocktrans %} {{request.scheme}}://{{request.META.HTTP_HOST}}{{request.path}}

{% blocktrans %}To get started, the first thing you want to do is define your configuration. Do this by clicking on the Configuration tab. {% endblocktrans %}

{% trans "Working With Your Configuration" %}
{% blocktrans %}The following command would cause apprise to retrieve the configuration loaded and send a test notification to all of your added services:{% endblocktrans %}
apprise --body="Test Message" --tag=all \
    --config={{request.scheme}}://{{request.META.HTTP_HOST}}{% url "get" key %}
{% trans "Loaded Configuration" %}

{% blocktrans %}Define your configuration below:{% endblocktrans %}

{{ form_cfg }}

{% blocktrans %} You can send a notification using the loaded configuration: {% endblocktrans %}

{{ form_notify }}

{% endblock %} {% block jsfooter %} async function update() { // disable the notification tab until we know for certain // a notification is possible document.querySelector('.config-overview li a[href="#notify"]') .parentNode.classList.add('disabled'); // Disable any has-config entries document.querySelector('.has-config') .style.display = 'none'; // Ensure we show our progress loader and reset our url list document.querySelector('#url-list').textContent = '' document.querySelector('#url-list-progress').style.display = null; // Ensure no-config sections are visible document.querySelector('.no-config') .style.display = null; // perform our status check let response = await fetch('{% url "get" key %}', { method: 'POST', }); let result = await response; if(response.status == 204) { // no problem; we simply have no content to retrieve return ''; } else if(response.status == 200) { // configuration found // Remove our restrictions on sending notifications document.querySelector('.config-overview li a[href="#notify"]') .parentNode.classList.remove('disabled'); // Set our configuration so it's visible response.text().then(function (text) { document.querySelector('#id_config').value = text; }); // Ensure has-config sections are visible document.querySelector('.has-config') .style.display = null; // Disable any no-config entries document.querySelector('.no-config') .style.display = 'none'; // perform a tag retrieval; start with 'all' let tags = ['all']; let jsonResponse = fetch('{% url "json_urls" key %}?privacy=1', { method: 'GET', }).then(function(jsonResponse) { return jsonResponse.json(); }).then(function (data) { // Initialize our tags making it easy for an end user to // choose from. Tags are based off ones found in the saved // configuration. let external_data = tags.concat(data.tags).reduce(function(result, item) { result[item] = null; return result; }, {}) M.Chips.init(document.querySelectorAll('.chips'), { placeholder: 'Optional Tag', secondaryPlaceholder: 'Another Tag', autocompleteOptions: { data: external_data, minLength: 0 }, onChipAdd: function(e, chip) { var $this = this; $this.chipsData.forEach(function(e, index) { if(!(e.tag in external_data)) $this.deleteChip(index); }) } }); // Now build our our loaded list of configuration for our welcome page let urlList = document.createElement('ul'); // Create a list item for each url retrieved data.urls.forEach(function (entry) { let code = document.createElement('code'); let li = document.createElement('li'); code.textContent = entry.url; li.setAttribute('class', 'card-panel'); li.appendChild(code); // Get our tags associate with the URL entry.tags.forEach(function (tag) { let chip = document.createElement('div'); chip.setAttribute('class', 'chip'); chip.textContent = `🏷️ ${tag}`; li.appendChild(chip); }); urlList.appendChild(li); }); // Store our new list document.querySelector('#url-list-progress').style.display = 'none'; document.querySelector('#url-list').textContent = '' if(urlList.childNodes.length > 0) { document.querySelector('#url-list').appendChild(urlList); } else { document.querySelector('#url-list').textContent = '{% trans "There are no Apprise URL(s) loaded." %}' } }).catch(function (err) { // There was an error document.querySelector('#url-list-progress').style.display = 'none'; document.querySelector('#url-list').textContent = '{% trans "An error occurred retrieving the list of loaded Apprise URL(s)" %}' }); return response; } // if we reach here, we failed return null; } update(); // over-ride manual submit for a nicer user experience document.querySelector('#addconfig').onsubmit = function(event) { event.preventDefault(); const form = this; const body = new URLSearchParams(new FormData(form)); // perform our status check let response = fetch('{% url "add" key %}', { method: 'POST', body: body, }).then(function(response) { if(response.status == 200) { // update our settings update(); // user notification Swal.fire( '{% trans "Save" %}', '{% trans "Successfully saved the specified URL(s)." %}', 'success' ); } else { // user notification Swal.fire( '{% trans "Save" %}', '{% trans "Failed to save the specified URL(s)." %}', 'error' ); } }); return false; } // over-ride manual submit for a nicer user experience document.querySelector('#donotify').onsubmit = function(event) { event.preventDefault(); const chipElement = document.querySelector('.chips'); chipElement.querySelector('.chips'); const chipInput = document.querySelector('.chips > input'); if(chipInput.value) { // This code just handles text typed in the tag section that was // not submitted. This forces any lingering un-committed text // into a tag just prior to it's submission const ev = new KeyboardEvent('keydown', { altKey:false, bubbles: true, cancelBubble: false, cancelable: true, charCode: 0, code: "Enter", composed: true, ctrlKey: false, currentTarget: null, defaultPrevented: true, detail: 0, eventPhase: 0, isComposing: false, isTrusted: true, key: "Enter", keyCode: 13, location: 0, metaKey: false, repeat: false, returnValue: false, shiftKey: false, type: "keydown", which: 13 }); chipInput.dispatchEvent(ev); } // store tags (as comma separated string) from materialize chip type into form document.querySelector('#id_tag').value = M.Chips.getInstance(chipElement).chipsData.reduce( function(s, a){ s.push(a.tag) return s; }, []).join(",") const form = this; const body = new URLSearchParams(new FormData(form)); // perform our notification Swal.fire( '{% trans "Notification" %}', '{% trans "Sending notification(s)..." %}', ); Swal.showLoading() let response = fetch('{% url "notify" key %}', { method: 'POST', body: body, }).then(function(response) { if(response.status == 200) { // user notification Swal.fire( '{% trans "Notification" %}', '{% trans "Successfully sent the notification(s)." %}', 'success' ); } else { // user notification Swal.fire( '{% trans "Notification" %}', '{% trans "Failed to send the notification(s)." %}', 'error' ); } }); return false; } {% endblock %} {% block onload %} {{ block.super }} document.querySelector('label [for="id_tag"]') { // create a new div with the class 'chips' assigned to it const element = document.createElement('div') let refNode = document.querySelector('label[for="id_tag"]') element.classList.add("chips") element.style.margin = '0' refNode.parentNode.insertBefore(element, refNode.nextSibling) } // Hide tag field since we use the pretty Materialize Chip setup instead document.querySelector('#id_tag').style.display = 'none'; {% endblock %}