├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── publish.yml ├── .gitignore ├── Makefile ├── README.md ├── archive ├── docker.labelInjector-2024.07.29.txz ├── docker.labelInjector-2024.07.31.txz ├── docker.labelInjector-2024.08.26.txz ├── docker.labelInjector-2024.08.28.txz ├── docker.labelInjector-2024.09.02.txz ├── docker.labelInjector-2024.09.30.txz ├── docker.labelInjector-2024.10.02.txz ├── docker.labelInjector-2024.10.03.txz ├── docker.labelInjector-2024.10.05.txz ├── docker.labelInjector-2024.10.29.txz └── docker.labelInjector-2024.11.03.txz ├── docker.labelInjector.plg ├── images ├── button.png ├── form.png └── settings.png ├── pkg_build.sh └── src └── docker.labelInjector └── usr └── local └── emhttp └── plugins └── docker.labelInjector ├── Readme.md ├── docker.labelInjector.Docker.page ├── docker.labelInjector.page ├── icon.png ├── scripts ├── config.js ├── docker.js └── dropdown.js ├── server ├── config │ └── DefaultLabels.php └── service │ └── AddLabels.php └── styles └── styles.css /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | Please include any labels you think may be causing the to help replicate 13 | 14 | **To Reproduce** 15 | Steps to reproduce the behavior: 16 | 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Unraid version** 29 | 30 | **Any logs** 31 | i.e 32 | 33 | * /var/log/phplog - for php error logs 34 | * right click and inspect check the console for js errors 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | publish: 8 | concurrency: 9 | group: publish 10 | cancel-in-progress: false 11 | permissions: 12 | id-token: write 13 | contents: write 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 17 | - name: Run pkg_build.sh 18 | run: bash pkg_build.sh 19 | - name: Commit and push changes 20 | uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1 21 | with: 22 | commit_message: 'Publish plg changes' 23 | file_pattern: 'archive/* *.plg' 24 | commit_user_name: 'phyzical[bot]' 25 | commit_user_email: '5182053+phyzical@users.noreply.github.com' 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | tmp 3 | .DS_Store 4 | .vscode 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -include .env 2 | DIR=/usr/local/emhttp/plugins/docker.versions 3 | SSH_HOST=${USERNAME}@${HOST} 4 | 5 | 6 | build: 7 | bash pkg_build.sh 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # docker.labelInjector 2 | 3 | Install via CA Apps 4 | 5 | You can add defaults to be prefilled each time via the settings page 6 | ![settings](images/settings.png) 7 | 8 | After installing, just click the "Add Labels" button 9 | 10 | ![button](images/button.png) 11 | 12 | Then simply choose the containers you want to add the label value combos to, to choose All for all. 13 | 14 | If the label exists already an update will be performed. 15 | 16 | If the label does not exist it will be added. 17 | 18 | If you enter a value of `REMOVE` it will instead remove the label if found. 19 | 20 | Special flags include: 21 | 22 | * will be replace with the magic value works with both key and value 23 | 24 | * `${CONTAINER_NAME}` 25 | 26 | Before it updates it will backup the template being used just incase something does go wrong. 27 | ![form](images/form.png) 28 | 29 | If you find this happen you should be able to restore the backup via `/boot/config/plugins/dockerMan/templates-user/my-TEMPLATE_NAME.DATE.bak` 30 | -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.07.29.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.07.29.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.07.31.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.07.31.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.08.26.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.08.26.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.08.28.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.08.28.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.09.02.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.09.02.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.09.30.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.09.30.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.10.02.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.10.02.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.10.03.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.10.03.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.10.05.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.10.05.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.10.29.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.10.29.txz -------------------------------------------------------------------------------- /archive/docker.labelInjector-2024.11.03.txz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/archive/docker.labelInjector-2024.11.03.txz -------------------------------------------------------------------------------- /docker.labelInjector.plg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ]> 12 | 13 | 14 | 15 | ###2024.11.03 16 | - Fix issue with default labels not being loaded correctly when first time use 17 | 18 | ###2024.10.29 19 | !!!! BREAKING CHANGE !!!! 20 | - Changed the way the default labels are stored. 21 | - If any of your exisiting default labels use ` -> " Going forward these must be escaped \` -> " 22 | 23 | ###2024.10.05 24 | - Fix visibility of changes in the summary when dark mode 25 | - Add remove all button during edit mode 26 | - Adjusted summary text to make it more obvious the sequence of events 27 | 28 | ###2024.10.02 29 | - Hard code options to be black text to avoid fighting dark mode 30 | - Fix permissions in archive being set to my user instead of none 31 | 32 | ###2024.09.30 33 | - Fix changlog 34 | - Add support for `${CONTAINER_NAME}` in label keys also 35 | 36 | ###2024.09.02 37 | - Adjusted how the All button works for container select 38 | - Fix alert using , instead of nothing 39 | 40 | ###2024.08.28 41 | - Added the ability to have quotes in labels by using ` backticks 42 | - Added a summary of changes modal so its just a little less magical 43 | 44 | ###2024.08.26 45 | - Added ability to add default labels via settings apge 46 | - Added ability to use '${CONTAINER_NAME}' to be auto replaced with the container name 47 | - Replaced select fields with choices select for better usability 48 | - Added logic to allow editing of labels in selects 49 | - Simplified the removal of a label to assume if its an empty label that it will be removed 50 | 51 | ###2024.07.31 52 | - Improved form styling 53 | - Added overview of selected containers 54 | - Added ability to see key and value of entered labels 55 | - Added colours for when adding or removing labels 56 | 57 | ###2024.07.29 58 | - Initial Release 59 | 60 | 61 | 62 | 63 | https://raw.github.com/&github;/main/archive/&name;-&version;.txz 64 | &md5; 65 | 66 | 67 | 68 | 69 | 70 | mkdir -p /boot/config/plugins/&name;/styles 71 | mkdir -p /boot/config/plugins/&name;/scripts 72 | rm -f $(ls /boot/config/plugins/&name;/&name;*.txz | grep -v '&version;') 73 | echo "&version;"> /boot/config/plugins/&name;/version 74 | echo "" 75 | echo "----------------------------------------------------" 76 | echo " &name; has been installed." 77 | echo " Version: &version;" 78 | echo "----------------------------------------------------" 79 | echo "" 80 | 81 | 82 | 83 | 84 | 85 | 86 | removepkg &name;-&version; 87 | rm -rf &plugdir; 88 | rm -rf /boot/config/plugins/&name; 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /images/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/images/button.png -------------------------------------------------------------------------------- /images/form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/images/form.png -------------------------------------------------------------------------------- /images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/images/settings.png -------------------------------------------------------------------------------- /pkg_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | plugin_name="docker.labelInjector" 4 | CWD=$(pwd) 5 | tmpdir="$CWD/tmp/tmp.$(($RANDOM * 19318203981230 + 40))" 6 | version=$(date +"%Y.%m.%d") 7 | filename="$CWD/archive/$plugin_name-$version.txz" 8 | rm "$filename" 9 | dayversion=$(ls "$CWD"/archive/$plugin_name-"$version"*.txz 2>/dev/null | wc -l) 10 | 11 | if [ "$dayversion" -gt 0 ]; then 12 | filename=$CWD/archive/$plugin_name-$version.$dayversion.txz 13 | fi 14 | mkdir -p "$tmpdir" 15 | 16 | rsync -av --progress src/$plugin_name/ "$tmpdir" --exclude .git --exclude tmp --exclude .env --exclude archive 17 | 18 | cd "$tmpdir" || exit 19 | 20 | tar_command="tar" 21 | sed_prefix="-i" 22 | 23 | if [[ "$(uname)" == "Darwin" ]]; then 24 | tar_command="gtar" 25 | sed_prefix="-i ''" 26 | fi 27 | $tar_command --owner=root --group=root -cJf "$filename" . 28 | 29 | cd - || exit 30 | 31 | if [[ "$(uname)" == "Darwin" ]]; then 32 | md5hash=$(md5 -q "$filename") 33 | else 34 | md5hash=$(md5sum "$filename" | awk '{ print $1 }') 35 | fi 36 | 37 | rm -rf "$tmpdir" 38 | 39 | sed "$sed_prefix" 's///' $plugin_name.plg 40 | sed "$sed_prefix" 's///' $plugin_name.plg 41 | 42 | echo "MD5: $(md5sum "$filename")" 43 | echo "once pushed install via https://raw.githubusercontent.com/phyzical/$plugin_name/main/$plugin_name.plg" 44 | 45 | $tar_command -tvf "$filename" 46 | 47 | # Check for ownership issues 48 | OWN=$($tar_command -tvf "$filename" | grep -v "root/root" | grep -v "root root") 49 | if [ -n "$OWN" ]; then 50 | echo "Ownership issues (should be root/root):" 51 | echo "$OWN" 52 | exit 1 53 | fi 54 | 55 | # Check for permission issues 56 | PERM=$($tar_command -tvf "$filename" | grep -v "rwxr-xr-x" | grep -v "rw-r--r--") 57 | if [ -n "$PERM" ]; then 58 | echo "Permission issues (should be rwxr-xr-x or rw-r--r--):" 59 | echo "$PERM" 60 | exit 1 61 | fi 62 | -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/Readme.md: -------------------------------------------------------------------------------- 1 | #### DockerVersions### DockerVersions will add a button next to updateable containers, and do its best to find changelogs to be displayed 2 | -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/docker.labelInjector.Docker.page: -------------------------------------------------------------------------------- 1 | Menu="Docker" 2 | Icon="server" 3 | --- 4 | 5 | 8 | 9 | 13 | 14 | 15 | "> 16 | 17 | 18 | 19 | 20 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/docker.labelInjector.page: -------------------------------------------------------------------------------- 1 | Menu="Utilities" 2 | Title="docker.labelInjector" 3 | Icon="icon.png" 4 | Markdown="false" 5 | --- 6 | 9 | 10 | 11 | 15 | 16 | 17 | "> 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phyzical/docker.labelInjector/19dd8e6f1189e681f966dbacee252f8758c459b1/src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/icon.png -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/scripts/config.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | generateDropdown('#labels', { 3 | addItemFilter: (value) => { 4 | return !!value && value !== '' && value.includes('=') 5 | }, 6 | customAddItemText: 'Only values containing "=" can be added, i.e `LABEL_A=VALUE_A', 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/scripts/docker.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | $("#docker_containers").after('') 3 | }) 4 | 5 | function labelFormPopup() { 6 | swal({ 7 | title: "Label Updater", 8 | text: '
', 9 | html: true, 10 | showCancelButton: true, 11 | closeOnConfirm: false, 12 | closeOnCancel: false 13 | }, function (isConfirm) { 14 | $('div.spinner.fixed').show(); 15 | // Remove the 'label-injector' class regardless of the button clicked 16 | $(".sweet-alert").removeClass("label-injector"); 17 | swal.close(); // Close the SweetAlert dialog 18 | if (isConfirm) { 19 | setTimeout(() => { 20 | $('div.spinner.fixed').hide(); 21 | addLabels(); 22 | }, 500); 23 | } else { 24 | $('div.spinner.fixed').hide(); 25 | } 26 | }); 27 | $(".sweet-alert").addClass("label-injector") 28 | 29 | labelForm() 30 | } 31 | 32 | function addLabels() { 33 | const labels = $('#label-injector-labels') 34 | .val() 35 | .map(value => ({ key: value.split("=")[0], value: value.split("=")[1] })); 36 | 37 | const containers = $('#label-injector-containers').val().filter(x => x !== 'All'); 38 | 39 | if (labels.length > 0 && containers.length > 0) { 40 | $('div.spinner.fixed').show(); 41 | $.post("/plugins/docker.labelInjector/server/service/AddLabels.php", { data: JSON.stringify({ labels, containers }) }, function (data) { 42 | $('div.spinner.fixed').hide(); 43 | data = JSON.parse(data) 44 | const hasUpdates = data.containers.length > 0 45 | let updates = ['
'];
 46 |             if (hasUpdates) {
 47 |                 updates.push("

Note: The templates have been updated, this is just an FYI modal at the moment

") 48 | updates.push("

Note: if you leave this page the label will not be applied until you edit and save the container/s in question

") 49 | updates.push("

Note: Performing this action will also update the container at this time

") 50 | updates.push("

Once you press okay the changes will be applied one by one

") 51 | Object.entries(data.updates).forEach(([container, changes]) => { 52 | updates.push(`

${container} changes:

${changes.join("")}`); 53 | }); 54 | } else { 55 | updates.push("

No Containers returned any changes in labels, nothing to be applied

") 56 | } 57 | 58 | updates.push("
") 59 | 60 | swal({ 61 | title: "Summary of Updates", 62 | text: updates.join(""), 63 | html: true, 64 | closeOnConfirm: false, 65 | }, function () { 66 | $(".sweet-alert").removeClass("label-injector-summary"); 67 | swal.close(); // Close the SweetAlert dialog 68 | if (hasUpdates) { 69 | $('div.spinner.fixed').show(); 70 | const containersString = data.containers.map(container => encodeURIComponent(container)); 71 | setTimeout(() => { 72 | $('div.spinner.fixed').hide(); 73 | openDocker('update_container ' + containersString.join("*"), _(`Updating ${data.containers.length} Containers`), '', 'loadlist'); 74 | }, 500); 75 | } 76 | }); 77 | $(".sweet-alert").addClass("label-injector-summary") 78 | }); 79 | } 80 | } 81 | 82 | function labelForm() { 83 | $('#label-injector-form').html(` 84 |
85 |
86 |

Choose containers to add labels to

87 | 88 | 89 |
90 |
91 |

Note:

92 | 99 |

The following special values are available replacement of values or keys:

100 | 103 | 104 | 105 |
106 |
107 | 108 | `) 109 | generateLabelsSelect(); 110 | generateContainersSelect(); 111 | 112 | $(".sa-confirm-button-container button").prop("disabled", true) 113 | const valueChecker = function () { 114 | if ($("#label-injector-containers").val() && $("#label-injector-labels").val()) { 115 | $(".sa-confirm-button-container button").prop("disabled", false) 116 | } else { 117 | $(".sa-confirm-button-container button").prop("disabled", true) 118 | } 119 | } 120 | $("#label-injector-containers").on('change', valueChecker); 121 | $("#label-injector-labels").on('change', valueChecker); 122 | } 123 | 124 | function generateLabelsSelect() { 125 | generateDropdown("#label-injector-labels", { 126 | choices: defaultLabels.map(label => ({ 127 | value: label, 128 | label: label, 129 | selected: true, 130 | disabled: false 131 | })), 132 | addItemFilter: (value) => !!value && value !== '' && value.includes('='), 133 | customAddItemText: 'Only values containing "=" can be added, i.e `LABEL_A=VALUE_A', 134 | }, "#remove-all-label-injector-labels") 135 | } 136 | 137 | function generateContainersSelect() { 138 | generateDropdown("#label-injector-containers", { 139 | choices: docker.map(ct => ({ 140 | value: ct.name, 141 | label: ct.name, 142 | selected: false, 143 | disabled: false 144 | })).concat({ 145 | value: 'all', 146 | label: 'All', 147 | selected: false, 148 | disabled: false 149 | }), 150 | }, "#remove-all-label-injector-containers") 151 | } -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/scripts/dropdown.js: -------------------------------------------------------------------------------- 1 | const defaultOptions = { 2 | silent: false, 3 | items: [], 4 | choices: [], 5 | renderChoiceLimit: -1, 6 | maxItemCount: -1, 7 | closeDropdownOnSelect: 'auto', 8 | singleModeForMultiSelect: false, 9 | addChoices: true, 10 | addItems: true, 11 | removeItems: true, 12 | removeItemButton: true, 13 | removeItemButtonAlignLeft: false, 14 | editItems: true, 15 | allowHTML: false, 16 | allowHtmlUserInput: false, 17 | duplicateItemsAllowed: true, 18 | delimiter: ',', 19 | paste: true, 20 | searchEnabled: true, 21 | searchChoices: true, 22 | searchFloor: 1, 23 | searchResultLimit: 4, 24 | searchFields: ['label', 'value'], 25 | position: 'auto', 26 | resetScrollPosition: true, 27 | shouldSort: true, 28 | shouldSortItems: false, 29 | shadowRoot: null, 30 | placeholder: true, 31 | placeholderValue: null, 32 | searchPlaceholderValue: null, 33 | prependValue: null, 34 | appendValue: null, 35 | renderSelectedChoices: 'auto', 36 | loadingText: 'Loading...', 37 | noResultsText: 'No results found', 38 | noChoicesText: 'No choices to choose from', 39 | itemSelectText: 'Press to select', 40 | uniqueItemText: 'Only unique values can be added', 41 | customAddItemText: 'Only values containing "=" can be added, i.e `LABEL_A=VALUE_A', 42 | addItemText: (value) => { 43 | return `Press Enter to add "${value}"`; 44 | }, 45 | removeItemIconText: () => `Remove item`, 46 | removeItemLabelText: (value) => `Remove item: ${value}`, 47 | maxItemText: (maxItemCount) => { 48 | return `Only ${maxItemCount} values can be added`; 49 | }, 50 | valueComparer: (value1, value2) => { 51 | return value1 === value2; 52 | }, 53 | classNames: { 54 | containerOuter: ['choices'], 55 | containerInner: ['choices__inner'], 56 | input: ['choices__input'], 57 | inputCloned: ['choices__input--cloned'], 58 | list: ['choices__list'], 59 | listItems: ['choices__list--multiple'], 60 | listSingle: ['choices__list--single'], 61 | listDropdown: ['choices__list--dropdown'], 62 | item: ['choices__item'], 63 | itemSelectable: ['choices__item--selectable'], 64 | itemDisabled: ['choices__item--disabled'], 65 | itemChoice: ['choices__item--choice'], 66 | description: ['choices__description'], 67 | placeholder: ['choices__placeholder'], 68 | group: ['choices__group'], 69 | groupHeading: ['choices__heading'], 70 | button: ['choices__button'], 71 | activeState: ['is-active'], 72 | focusState: ['is-focused'], 73 | openState: ['is-open'], 74 | disabledState: ['is-disabled'], 75 | highlightedState: ['is-highlighted'], 76 | selectedState: ['is-selected'], 77 | flippedState: ['is-flipped'], 78 | loadingState: ['is-loading'], 79 | notice: ['choices__notice'], 80 | addChoice: ['choices__item--selectable', 'add-choice'], 81 | noResults: ['has-no-results'], 82 | noChoices: ['has-no-choices'], 83 | }, 84 | // Choices uses the great Fuse library for searching. You 85 | // can find more options here: https://fusejs.io/api/options.html 86 | fuseOptions: { 87 | includeScore: true 88 | }, 89 | labelId: '', 90 | callbackOnInit: null, 91 | callbackOnCreateTemplates: null, 92 | appendGroupInSearch: false, 93 | } 94 | 95 | function generateDropdown(selector, options, removeAllSelector = undefined) { 96 | const choicesSelect = new Choices($(selector)[0], { ...defaultOptions, ...options }); 97 | 98 | if (removeAllSelector === undefined) { 99 | return choicesSelect; 100 | } 101 | $(removeAllSelector).on('click', () => { 102 | const allItems = choicesSelect.getValue(true); 103 | allItems.forEach(item => { 104 | choicesSelect.removeActiveItemsByValue(item); 105 | }); 106 | }); 107 | 108 | 109 | let selectedAll = false; 110 | $(selector).on('change', function () { 111 | if ($(this).val().includes('all')) { 112 | if (!selectedAll) { 113 | selectedAll = true 114 | const allChoices = choices._store.choices; 115 | allChoices.forEach(choice => { 116 | if (!choice.selected && !choice.disabled) { 117 | choices.setChoiceByValue(choice.value); 118 | } 119 | }); 120 | } 121 | } else { 122 | if (selectedAll) { 123 | selectedAll = false 124 | const allChoices = choices._store.choices; 125 | allChoices.forEach(choice => { 126 | if (choice.selected && !choice.disabled) { 127 | choices.removeActiveItemsByValue(choice.value); 128 | } 129 | }); 130 | } 131 | } 132 | }) 133 | } -------------------------------------------------------------------------------- /src/docker.labelInjector/usr/local/emhttp/plugins/docker.labelInjector/server/config/DefaultLabels.php: -------------------------------------------------------------------------------- 1 | $labels]); 22 | mkdir(DefaultLabels::CONFIG_PATH, 0755, true); 23 | file_put_contents(DefaultLabels::LABELS_PATH, $labelsJson); 24 | return "Labels saved successfully!"; 25 | } 26 | return null; 27 | } 28 | 29 | 30 | /** 31 | * Get the default labels from the config file. 32 | * @return string[] 33 | */ 34 | static function getDefaultLabels(): array 35 | { 36 | $json = ""; 37 | if (file_exists(self::LABELS_PATH)) { 38 | $json = file_get_contents(self::LABELS_PATH); 39 | } 40 | if (!$json || empty($json)) { 41 | return []; 42 | } 43 | 44 | return array_map(function ($item) { 45 | return str_replace('"', self::QUOTE_REPLACER, $item); 46 | }, json_decode($json)->labels); 47 | } 48 | 49 | /** 50 | * Generate the form for the default labels. 51 | */ 52 | // TODO: reuse the form select config and here 53 | static function generateForm(): void 54 | { 55 | $message = self::formSubmit(); 56 | echo <<Default Labels 58 |

Labels to be prefilled when using the add labels button

59 |

Type and press enter to save a label, separate label from value via '='

60 |

Empty values are valid to allow for easy filling

61 | HTML; 62 | 63 | echo "

To use quotes in an options use an escaped backtick " . self::QUOTE_REPLACER . " Otherwise the option fails to save

"; 64 | echo <<The following special values are available:

67 | 70 |
71 |
72 | 73 |