diff options
Diffstat (limited to 'web_src')
-rw-r--r-- | web_src/css/index.css | 1 | ||||
-rw-r--r-- | web_src/css/modules/select.css | 25 | ||||
-rw-r--r-- | web_src/js/components/ScopedAccessTokenSelector.vue | 187 |
3 files changed, 107 insertions, 106 deletions
diff --git a/web_src/css/index.css b/web_src/css/index.css index 689c3f4a29..c9cc1d8032 100644 --- a/web_src/css/index.css +++ b/web_src/css/index.css @@ -1,6 +1,7 @@ @import "./modules/normalize.css"; @import "./modules/animations.css"; @import "./modules/button.css"; +@import "./modules/select.css"; @import "./modules/tippy.css"; @import "./modules/modal.css"; @import "./modules/breadcrumb.css"; diff --git a/web_src/css/modules/select.css b/web_src/css/modules/select.css new file mode 100644 index 0000000000..57a87888e0 --- /dev/null +++ b/web_src/css/modules/select.css @@ -0,0 +1,25 @@ +.gitea-select { + position: relative; +} + +.gitea-select select { + appearance: none; /* hide default triangle */ +} + +/* ::before and ::after pseudo elements don't work on select elements, + so we need to put it on the parent. */ +.gitea-select::after { + position: absolute; + top: 12px; + right: 8px; + pointer-events: none; + content: ''; + width: 14px; + height: 14px; + mask-size: cover; + -webkit-mask-size: cover; + mask-image: var(--octicon-chevron-right); + -webkit-mask-image: var(--octicon-chevron-right); + transform: rotate(90deg); /* point the chevron down */ + background: currentcolor; +} diff --git a/web_src/js/components/ScopedAccessTokenSelector.vue b/web_src/js/components/ScopedAccessTokenSelector.vue index 769f3262b4..b4b9b979ea 100644 --- a/web_src/js/components/ScopedAccessTokenSelector.vue +++ b/web_src/js/components/ScopedAccessTokenSelector.vue @@ -1,97 +1,100 @@ <template> - <div class="scoped-access-token-category"> - <div class="field gt-pl-2"> - <label class="checkbox-label"> - <input - ref="category" - v-model="categorySelected" - class="scope-checkbox scoped-access-token-input" - type="checkbox" - name="scope" - :value="'write:' + category" - @input="onCategoryInput" - > - {{ category }} - </label> - </div> - <div class="field gt-pl-4"> - <div class="inline field"> - <label class="checkbox-label"> - <input - ref="read" - v-model="readSelected" - :disabled="disableIndividual || writeSelected" - class="scope-checkbox scoped-access-token-input" - type="checkbox" - name="scope" - :value="'read:' + category" - @input="onIndividualInput" - > - read:{{ category }} - </label> - </div> - <div class="inline field"> - <label class="checkbox-label"> - <input - ref="write" - v-model="writeSelected" - :disabled="disableIndividual" - class="scope-checkbox scoped-access-token-input" - type="checkbox" - name="scope" - :value="'write:' + category" - @input="onIndividualInput" - > - write:{{ category }} - </label> - </div> + <div v-for="category in categories" :key="category" class="field gt-pl-2 gt-pb-2 access-token-category"> + <label class="category-label" :for="'access-token-scope-' + category"> + {{ category }} + </label> + <div class="gitea-select"> + <select + class="ui selection access-token-select" + name="scope" + :id="'access-token-scope-' + category" + > + <option value=""> + {{ noAccessLabel }} + </option> + <option :value="'read:' + category"> + {{ readLabel }} + </option> + <option :value="'write:' + category"> + {{ writeLabel }} + </option> + </select> </div> </div> </template> <script> import {createApp} from 'vue'; -import {showElem} from '../utils/dom.js'; +import {hideElem, showElem} from '../utils/dom.js'; const sfc = { props: { - category: { + isAdmin: { + type: Boolean, + required: true, + }, + noAccessLabel: { + type: String, + required: true, + }, + readLabel: { + type: String, + required: true, + }, + writeLabel: { type: String, required: true, }, }, - data: () => ({ - categorySelected: false, - disableIndividual: false, - readSelected: false, - writeSelected: false, - }), + computed: { + categories() { + const categories = [ + 'activitypub', + ]; + if (this.isAdmin) { + categories.push('admin'); + } + categories.push( + 'issue', + 'misc', + 'notification', + 'organization', + 'package', + 'repository', + 'user'); + return categories; + } + }, + + mounted() { + document.getElementById('scoped-access-submit').addEventListener('click', this.onClickSubmit); + }, + + unmounted() { + document.getElementById('scoped-access-submit').removeEventListener('click', this.onClickSubmit); + }, methods: { - /** - * When entire category is toggled - * @param {Event} e - */ - onCategoryInput(e) { + onClickSubmit(e) { e.preventDefault(); - this.disableIndividual = this.$refs.category.checked; - this.writeSelected = this.$refs.category.checked; - this.readSelected = this.$refs.category.checked; - }, - /** - * When an individual level of category is toggled - * @param {Event} e - */ - onIndividualInput(e) { - e.preventDefault(); - if (this.$refs.write.checked) { - this.readSelected = true; + const warningEl = document.getElementById('scoped-access-warning'); + // check that at least one scope has been selected + for (const el of document.getElementsByClassName('access-token-select')) { + if (el.value) { + // Hide the error if it was visible from previous attempt. + hideElem(warningEl); + // Submit the form. + document.getElementById('scoped-access-form').submit(); + // Don't show the warning. + return; + } } - this.categorySelected = this.$refs.write.checked; - }, - } + // no scopes selected, show validation error + showElem(warningEl); + } + }, }; export default sfc; @@ -100,39 +103,11 @@ export default sfc; * Initialize category toggle sections */ export function initScopedAccessTokenCategories() { - for (const el of document.getElementsByTagName('scoped-access-token-category')) { - const category = el.getAttribute('category'); - createApp(sfc, { - category, - }).mount(el); + for (const el of document.getElementsByClassName('scoped-access-token-mount')) { + createApp({}) + .component('scoped-access-token-selector', sfc) + .mount(el); } - - document.getElementById('scoped-access-submit')?.addEventListener('click', (e) => { - e.preventDefault(); - // check that at least one scope has been selected - for (const el of document.getElementsByClassName('scoped-access-token-input')) { - if (el.checked) { - document.getElementById('scoped-access-form').submit(); - } - } - // no scopes selected, show validation error - showElem(document.getElementById('scoped-access-warning')); - }); } </script> - -<style scoped> -.scoped-access-token-category { - padding-top: 10px; - padding-bottom: 10px; -} - -.checkbox-label { - cursor: pointer; -} - -.scope-checkbox { - margin: 4px 5px 0 0; -} -</style> |