- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
- <fieldset id="ldapWizard4">
- <div>
- <p>
- {{ t('user_ldap', 'Groups meeting these criteria are available in %s:', {themeName: theme.getName()}) }}
- </p>
- <p>
- <label for="ldap_groupfilter_objectclass">
- {{ t('user_ldap', 'Only these object classes:') }}
- </label>
+ <fieldset class="ldap-wizard__groups">
+ {{ t('user_ldap', 'Groups meeting these criteria are available in {instanceName}:', {instanceName}) }}
- <select id="ldap_groupfilter_objectclass"
- multiple="multiple"
- name="ldap_groupfilter_objectclass"
- class="multiSelectPlugin" />
- </p>
- <p>
- <label for="ldap_groupfilter_groups">
- {{ t('user_ldap', 'Only from these groups:') }}
- </label>
+ <div class="ldap-wizard__groups__line ldap-wizard__groups__filter-selection">
+ <NcSelect v-model="ldapConfig.ldapGroupFilterObjectClass"
+ class="ldap-wizard__groups__group-filter-groups__select"
+ :options="['TODO']"
+ :disable="allowUserFilterGroupsSelection"
+ :input-label="t('user_ldap', 'Only these object classes:')"
+ :multiple="true" />
- <input type="text" class="ldapManyGroupsSupport ldapManyGroupsSearch hidden" placeholder="t('user_ldap', 'Search groups')">
+ <!-- <input type="text" class="ldapManyGroupsSupport ldapManyGroupsSearch hidden" placeholder="t('user_ldap', 'Search groups')"> -->
+ <NcSelect v-model="ldapConfig.ldapGroupFilterObjectClass"
+ class="ldap-wizard__groups__group-filter-groups__select"
+ :options="['TODO']"
+ :disable="allowUserFilterGroupsSelection"
+ :input-label="t('user_ldap', 'Only from these groups:')"
+ :multiple="true" />
+ </div>
- <select id="ldap_groupfilter_groups"
- multiple="multiple"
- name="ldap_groupfilter_groups"
- class="multiSelectPlugin" />
- </p>
+ <!-- TODO -->
+ <div class="ldap-wizard__groups__line">
<p class="ldapManyGroupsSupport hidden">
- <label />
<select class="ldapGroupList ldapGroupListAvailable"
multiple="multiple"
aria-describedby="ldapGroupListAvailable_instructions"
title="t('user_ldap', 'Available groups')" />
- </p><p id="ldapGroupListAvailable_instructions" class="hidden-visually">
+ </p>
+ <p id="ldapGroupListAvailable_instructions" class="hidden-visually">
{{ t('user_ldap', 'Available groups') }}
</p>
- <span class="buttonSpan">
- <NcButton class="ldapGroupListSelect" type="button">></NcButton><br>
- <NcButton class="ldapGroupListDeselect" type="button"><</NcButton>
+
+ <span>
+ <NcButton class="ldapGroupListSelect">></NcButton><br>
+ <NcButton class="ldapGroupListDeselect"><</NcButton>
</span>
+
<select class="ldapGroupList ldapGroupListSelected"
multiple="multiple"
aria-describedby="ldapGroupListSelected_instructions"
<p id="ldapGroupListSelected_instructions" class="hidden-visually">
{{ t('user_ldap', 'Selected groups') }}
</p>
- <p>
- <label><a id="toggleRawGroupFilter" class="ldapToggle">↓ {{ t('user_ldap', 'Edit LDAP Query') }}</a></label>
- </p>
- <p id="ldapReadOnlyGroupFilterContainer" class="hidden ldapReadOnlyFilterContainer">
- <label>{{ t('user_ldap', 'LDAP Filter:') }}</label>
- <span class="ldapFilterReadOnlyElement ldapInputColElement" />
- </p>
- <p id="rawGroupFilterContainer" class="invisible">
- <textarea id="ldap_group_filter"
- type="text"
- name="ldap_group_filter"
- placeholder="t('user_ldap', 'Edit LDAP Query')"
- aria-describedby="rawGroupFilterContainer_instructions"
- title="t('user_ldap', 'The filter specifies which LDAP groups shall have access to the {themeName} instance.', {themeName: theme.getName()}) }}" />
- </p><p id="rawGroupFilterContainer_instructions" class="hidden-visually">
- {{ t('user_ldap', 'The filter specifies which LDAP groups shall have access to the {themeName} instance.', {themeName: theme.getName()}) }}
- </p>
+ </div>
+
+ <div class="ldap-wizard__groups__line ldap-wizard__groups__groups-filter">
+ <NcCheckboxRadioSwitch :checked.sync="editGroupsFilter">
+ {{ t('user_name', 'Edit LDAP Query') }}
+ </NcCheckboxRadioSwitch>
- <p />
- <div class="ldapWizardInfo invisible">
-
+ <div v-if="!editGroupsFilter">
+ <label>{{ t('user_name', 'LDAP Filter:') }}</label>
+ <span>{{ ldapConfig.ldapGroupsListFilter }}</span>
</div>
- <p class="ldap_count">
- <NcButton class="ldapGetEntryCount ldapGetGroupCount" name="ldapGetEntryCount" type="button">
- {{ t('user_ldap', 'Verify settings and count the groups') }}
- </NcButton>
- <span id="ldap_group_count" />
- </p>
+ <div v-else>
+ <NcTextArea :value.sync="ldapConfig.ldapGroupListFilter"
+ :placeholder="t('user_name', 'Edit LDAP Query')"
+ :helper-text="t('user_name', 'The filter specifies which LDAP groups shall have access to the {instanceName} instance.', {instanceName})" />
+ </div>
+ </div>
+
+ <div class="ldap-wizard__groups__line ldap-wizard__groups__groups-count-check">
+ <NcButton @click="getGroupsCount">
+ {{ t('user_ldap', 'Verify settings and count the groups') }}
+ </NcButton>
- <!-- TODO: What is this -->
- {{ wizardControls }}
+ <span v-if="groupsCount !== undefined">{{ t('user_ldap', "Groups count: {groupsCount}", { groupsCount }) }}</span>
</div>
</fieldset>
</template>
<script lang="ts" setup>
-import { defineProps, PropType } from 'vue'
+import { defineProps, computed, ref } from 'vue'
import { t } from '@nextcloud/l10n'
-import { NcButton } from '@nextcloud/vue'
+import { NcButton, NcTextArea, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'
-import { LDAPConfig } from '../../services/ldapConfigService';
+import { useLDAPConfigStore } from '../../store/config'
-const { ldapConfig } = defineProps({
- ldapConfig: {
- type: Object as PropType<LDAPConfig>,
+const ldapConfigStore = useLDAPConfigStore()
+
+const { ldapConfigId } = defineProps({
+ ldapConfigId: {
+ type: String,
required: true,
},
})
-const wizardControls = ''
-const theme = {
- getName() {
- return 'TODO'
- },
+const ldapConfig = computed(() => ldapConfigStore.ldapConfigs[ldapConfigId])
+
+const instanceName = 'TODO'
+
+const groupsCount = ref<number>(-1)
+const editGroupsFilter = ref(false)
+const allowUserFilterGroupsSelection = ref(false)
+
+/**
+ *
+ */
+async function getGroupsCount() {
+ groupsCount.value++ // TODO: Implement
}
</script>
+<style lang="scss" scoped>
+.ldap-wizard__groups {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+
+ &__line {
+ display: flex;
+ align-items: start;
+ }
+
+ &__filter-selection {
+ flex-direction: column;
+ }
+
+ &__groups-filter {
+ display: flex;
+ flex-direction: column;
+ }
+
+ &__groups-count-check {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ }
+}
+</style>
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
- <fieldset id="ldapWizard3">
- <div>
- <p>
- {{ t('user_ldap', 'When logging in, %s will find the user based on the following attributes:', { themeName: theme.getName() }) }}
- </p>
- <p>
- <label for="ldap_loginfilter_username">
- {{ t('user_ldap', 'LDAP/AD Username:') }}
- </label>
-
- <input id="ldap_loginfilter_username"
- type="checkbox"
- aria-describedby="ldap_loginfilter_username_instructions"
- name="ldap_loginfilter_username"
- value="1">
- </p>
- <p id="ldap_loginfilter_username_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Allows login against the LDAP/AD username, which is either "uid" or "sAMAccountName" and will be detected.') }}
- </p>
- <p>
- <label for="ldap_loginfilter_email">
- {{ t('user_ldap', 'LDAP/AD Email Address:') }}
- </label>
-
- <input id="ldap_loginfilter_email"
- type="checkbox"
- aria-describedby="ldap_loginfilter_email_instructions"
- name="ldap_loginfilter_email"
- value="1">
- </p><p id="ldap_loginfilter_email_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Allows login against an email attribute. "mail" and "mailPrimaryAddress" allowed.') }}
- </p>
- <p>
- <label for="ldap_loginfilter_attributes">
- {{ t('user_ldap', 'Other Attributes:') }}
- </label>
-
- <select id="ldap_loginfilter_attributes"
- multiple="multiple"
- name="ldap_loginfilter_attributes"
- class="multiSelectPlugin" />
- </p>
- <p>
- <label><a id="toggleRawLoginFilter" class="ldapToggle">↓ {{ t('user_ldap', 'Edit LDAP Query') }}</a></label>
- </p>
- <p id="ldapReadOnlyLoginFilterContainer" class="hidden ldapReadOnlyFilterContainer">
- <label>{{ t('user_ldap', 'LDAP Filter:') }}</label>
- <span class="ldapFilterReadOnlyElement ldapInputColElement" />
- </p>
- <p id="rawLoginFilterContainer" class="invisible">
- <textarea id="ldap_login_filter"
- type="text"
- name="ldap_login_filter"
- class="ldapFilterInputElement"
- :placeholder="t('user_ldap', 'Edit LDAP Query')"
- aria-describedby="ldap_login_filter_instructions" />
- </p><p id="ldap_login_filter_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Defines the filter to apply, when login is attempted. \"%%uid\" replaces the username in the login action. Example: \"uid=%%uid\"') }}
- </p>
- <p /><div class="ldapWizardInfo invisible">
-
+ <fieldset class="ldap-wizard__login">
+ {{ t('user_ldap', 'When logging in, {instanceName} will find the user based on the following attributes:', { instanceName }) }}
+
+ <div class="ldap-wizard__login__line ldap-wizard__login__login-attributes">
+ <NcCheckboxRadioSwitch :checked.sync="ldapConfig.ldapUsername"
+ :aria-label="t('user_ldap', 'Allows login against the LDAP/AD username, which is either `uid` or `sAMAccountName` and will be detected.')">
+ {{ t('user_ldap', 'LDAP/AD Username') }}
+ </NcCheckboxRadioSwitch>
+
+ <NcCheckboxRadioSwitch :checked.sync="ldapConfig.ldapEmail"
+ :aria-label="t('user_ldap', 'Allows login against an email attribute. `mail` and `mailPrimaryAddress` allowed.')">
+ {{ t('user_ldap', 'LDAP/AD Email Address') }}
+ </NcCheckboxRadioSwitch>
+
+ <NcSelect v-model="ldapConfig.ldapLoginFilterAttributes"
+ :options="['TODO']"
+ :input-label="t('user_ldap', 'Other Attributes:')"
+ :multiple="true" />
+ </div>
+
+ <div class="ldap-wizard__login__line ldap-wizard__login__user-login-filter">
+ <NcCheckboxRadioSwitch :checked.sync="editUserLoginFilter">
+ {{ t('user_name', 'Edit LDAP Query') }}
+ </NcCheckboxRadioSwitch>
+
+ <div v-if="!editUserLoginFilter">
+ <label>{{ t('user_name', 'LDAP Filter:') }}</label>
+ <span>{{ ldapConfig.ldapUserLoginFilter }}</span>
+ </div>
+ <div v-else>
+ <NcTextArea :value.sync="ldapConfig.ldapUserLoginFilter"
+ :placeholder="t('user_name', 'Edit LDAP Query')"
+ :helper-text="t('user_name', 'Defines the filter to apply, when login is attempted. `%%uid` replaces the username in the login action. Example: `uid=%%uid`')" />
</div>
- <p class="ldap_verify">
- <input id="ldap_test_loginname"
- type="text"
- name="ldap_test_loginname"
- :placeholder="t('user_ldap', 'Test Loginname')"
- class="ldapVerifyInput"
- aria-describedby="ldap_test_loginname_instructions">
- </p><p id="ldap_test_loginname_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Attempts to receive a DN for the given loginname and the current login filter') }}
- </p>
- <NcButton class="ldapVerifyLoginName"
- name="ldapTestLoginSettings"
- type="button"
- disabled="disabled">
+ </div>
+
+ <div class="ldap-wizard__login__line">
+ <NcTextField :value.sync="testUsername"
+ :helper-text="t('user_ldap', 'Attempts to receive a DN for the given loginname and the current login filter')"
+ :placeholder="t('user_ldap', 'Test Loginname')"
+ autocomplete="off" />
+
+ <NcButton :disabled="enableVerifyButton"
+ @click="verifyLoginName">
{{ t('user_ldap', 'Verify settings') }}
</NcButton>
-
- <!-- TODO: What is this -->
- {{ wizardControls }}
</div>
</fieldset>
</template>
<script lang="ts" setup>
-import { defineProps, PropType } from 'vue'
+import { defineProps, computed, ref } from 'vue'
import { t } from '@nextcloud/l10n'
-import { NcButton } from '@nextcloud/vue'
+import { NcButton, NcTextField, NcTextArea, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'
+
+import { useLDAPConfigStore } from '../../store/config'
-import { LDAPConfig } from '../../services/ldapConfigService';
+const ldapConfigStore = useLDAPConfigStore()
-const { ldapConfig } = defineProps({
- ldapConfig: {
- type: Object as PropType<LDAPConfig>,
+const { ldapConfigId } = defineProps({
+ ldapConfigId: {
+ type: String,
required: true,
},
})
-const wizardControls = ''
-const theme = {
- getName() {
- return 'TODO'
- },
+const ldapConfig = computed(() => ldapConfigStore.ldapConfigs[ldapConfigId])
+
+const instanceName = 'TODO'
+const testUsername = ref('TODO')
+const enableVerifyButton = ref(false)
+const editUserLoginFilter = ref(false)
+
+/**
+ *
+ */
+async function verifyLoginName() {
+ // TODO: Implement
}
</script>
+<style lang="scss" scoped>
+.ldap-wizard__login {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+
+ button {
+ flex-shrink: 0;
+ }
+
+ &__line {
+ display: flex;
+ align-items: start;
+ }
+
+ &__login-attributes {
+ display: flex;
+ flex-direction: column;
+ }
+
+ &__user-login-filter {
+ display: flex;
+ flex-direction: column;
+ }
+}
+</style>
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
- <fieldset id="ldapWizard1">
- <NcButton id="ldap_action_copy_configuration"
- type="button"
- name="ldap_action_copy_configuration"
- aria-describedby="ldap_action_copy_configuration_instructions"
- class="ldapIconCopy icon-default-style"
- :title="t('user_ldap', 'Copy current configuration into new directory binding')">
- <template #icon>
- <ContentCopy :size="20" />
- </template>
- </NcButton>
- <p id="ldap_action_copy_configuration_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Copy current configuration into new directory binding') }}
- </p>
- <NcButton id="ldap_action_delete_configuration"
- type="button"
- aria-describedby="ldap_action_delete_configuration_instructions"
- name="ldap_action_delete_configuration"
- class="icon-delete icon-default-style"
- :title="t('user_ldap', 'Delete the current configuration')">
- <template #icon>
- <Delete :size="20" />
- </template>
- </NcButton>
- <p id="ldap_action_delete_configuration_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Delete the current configuration') }}
- </p>
-
- <div class="hostPortCombinator">
- <div class="tablerow">
- <div class="tablecell">
- <div class="table">
- <NcTextField id="ldap_host"
- class="host"
- :value.sync="ldapConfig.ldapHost"
- :helper-text="t('user_ldap', 'You can omit the protocol, unless you require SSL. If so, start with ldaps://')"
- :placeholder="t('user_ldap', 'Host')"
- autocomplete="off" />
- <span class="hostPortCombinatorSpan">
- <input id="ldap_port"
- type="number"
- name="ldap_port"
- :placeholder="t('user_ldap', 'Port')">
- <NcButton class="ldapDetectPort" name="ldapDetectPort" @click="detectPort">
- {{ t('user_ldap', 'Detect Port') }}
- </NcButton>
- </span>
- </div>
- </div>
- </div>
- <div class="tablerow">
-
- </div>
- <div class="tablerow">
- <NcTextField id="ldap_dn"
- class="tablecell"
- :value.sync="ldapConfig.ldapAgentName"
- :helper-text="t('user_ldap', 'The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty.')"
- :placeholder="t('user_ldap', 'User DN')"
- autocomplete="off" />
- </div>
+ <fieldset class="ldap-wizard__server">
+ <div class="ldap-wizard__server__line">
+ <NcButton :aria-label="t('user_ldap', 'Copy current configuration into new directory binding')"
+ @click="() => ldapConfigStore.copy(ldapConfigId)">
+ <template #icon>
+ <ContentCopy :size="20" />
+ </template>
+ </NcButton>
+ <NcButton :aria-label="t('user_ldap', 'Delete the current configuration')"
+ @click="() => ldapConfigStore.remove(ldapConfigId)">
+ <template #icon>
+ <Delete :size="20" />
+ </template>
+ </NcButton>
+ </div>
- <div class="tablerow">
- <NcTextField id="ldap_agent_password"
- type="password"
- class="tablecell"
- :helper-text="t('user_ldap', 'For anonymous access, leave DN and Password empty.')"
- :value.sync="ldapConfig.ldapAgentPassword"
- :placeholder="t('user_ldap', 'Password')"
+ <div class="ldap-wizard__server__line">
+ <NcTextField :value.sync="ldapConfig.ldapHost"
+ :helper-text="t('user_ldap', 'You can omit the protocol, unless you require SSL. If so, start with ldaps://')"
+ :placeholder="t('user_ldap', 'Host')"
+ autocomplete="off" />
+ <div class="ldap-wizard__server__host__port">
+ <NcTextField :value.sync="ldapConfig.ldapPort"
+ :placeholder="t('user_ldap', 'Port')"
+ type="number"
autocomplete="off" />
-
- <NcButton class="ldapSaveAgentCredentials" name="ldapSaveAgentCredentials" @click="ldapConfigStore.create(ldapConfig)">
- {{ t('user_ldap', 'Save Credentials') }}
+ <NcButton @click="detectPort">
+ {{ t('user_ldap', 'Detect Port') }}
</NcButton>
</div>
+ </div>
- <div id="ldap_base" class="tablecell">
- <NcTextArea label="Text area"
- :placeholder="t('user_ldap', 'One Base DN per line')"
- helper-text="t('user_ldap', 'You can specify Base DN for users and groups in the Advanced tab')" />
+ <div class="ldap-wizard__server__line">
+ <NcTextField :value.sync="ldapConfig.ldapAgentName"
+ :helper-text="t('user_ldap', 'The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty.')"
+ :placeholder="t('user_ldap', 'User DN')"
+ autocomplete="off" />
+ </div>
- <NcButton class="ldapDetectBase" name="ldapDetectBase" type="button">
- {{ t('user_ldap', 'Detect Base DN') }}
- </NcButton>
- <NcButton class="ldapTestBase" name="ldapTestBase" type="button">
- {{ t('user_ldap', 'Test Base DN') }}
- </NcButton>
- </div>
+ <div class="ldap-wizard__server__line">
+ <NcTextField type="password"
+ :helper-text="t('user_ldap', 'For anonymous access, leave DN and Password empty.')"
+ :value.sync="ldapConfig.ldapAgentPassword"
+ :placeholder="t('user_ldap', 'Password')"
+ autocomplete="off" />
- <div class="tablerow left">
- <input id="ldap_experienced_admin"
- type="checkbox"
- value="1"
- name="ldap_experienced_admin"
- class="tablecell"
- aria-describedby="ldap_experienced_admin_instructions"
- :title="t('user_ldap', 'Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge.')">
- <p id="ldap_experienced_admin_instructions" class="hidden-visually">
- {{ t('user_ldap', 'Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge.') }}
- </p>
- <label for="ldap_experienced_admin" class="tablecell">
- {{ t('user_ldap', 'Manually enter LDAP filters (recommended for large directories)') }}
- </label>
- </div>
+ <NcButton @click="ldapConfigStore.create(ldapConfig)">
+ {{ t('user_ldap', 'Save Credentials') }}
+ </NcButton>
</div>
- <!-- TODO: What is this -->
- {{ wizardControls }}
+ <div class="ldap-wizard__server__line">
+ <NcTextArea :label="t('user_ldap', 'Base DN')"
+ :value.sync="ldapConfig.ldapBase"
+ :placeholder="t('user_ldap', 'One Base DN per line')"
+ :helper-text="t('user_ldap', 'You can specify Base DN for users and groups in the Advanced tab')" />
+
+ <NcButton @click="detectBaseDN">
+ {{ t('user_ldap', 'Detect Base DN') }}
+ </NcButton>
+ <NcButton @click="testBaseDN">
+ {{ t('user_ldap', 'Test Base DN') }}
+ </NcButton>
+ </div>
+
+ <div class="ldap-wizard__server__line">
+ <NcCheckboxRadioSwitch :checked.sync="advancedAdmin"
+ :aria-label="t('user_ldap', 'Avoids automatic LDAP requests. Better for bigger setups, but requires some LDAP knowledge.')">
+ {{ t('user_ldap', 'Manually enter LDAP filters (recommended for large directories)') }}
+ </NcCheckboxRadioSwitch>
+ </div>
</fieldset>
</template>
<script lang="ts" setup>
-import { defineProps, PropType } from 'vue'
+import { defineProps, computed, ref } from 'vue'
import ContentCopy from 'vue-material-design-icons/ContentCopy.vue'
import Delete from 'vue-material-design-icons/Delete.vue'
import { t } from '@nextcloud/l10n'
-import { NcButton } from '@nextcloud/vue'
+import { NcButton, NcTextField, NcTextArea, NcCheckboxRadioSwitch } from '@nextcloud/vue'
-import { LDAPConfig } from '../../models'
import { useLDAPConfigStore } from '../../store/config'
const ldapConfigStore = useLDAPConfigStore()
-const { ldapConfig } = defineProps({
- ldapConfig: {
- type: Object as PropType<LDAPConfig>,
+const { ldapConfigId } = defineProps({
+ ldapConfigId: {
+ type: String,
required: true,
},
})
-const wizardControls = ''
+const ldapConfig = computed(() => ldapConfigStore.ldapConfigs[ldapConfigId])
+
+// TODO: use this
+const advancedAdmin = ref(false)
+
+/**
+ *
+ */
+async function detectPort() {
+ // TODO
+}
+
+/**
+ *
+ */
+async function detectBaseDN() {
+ // TODO
+}
+
+/**
+ *
+ */
+async function testBaseDN() {
+ // TODO
+}
</script>
+<style lang="scss" scoped>
+.ldap-wizard__server {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+
+ button {
+ flex-shrink: 0;
+ }
+
+ &__line {
+ display: flex;
+ align-items: start;
+ gap: 16px;
+ }
+
+ &__host__port {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+ gap: 16px;
+ }
+}
+</style>
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
- <fieldset id="ldapWizard2">
- <div>
- <p>
- {{ t('user_name', 'Listing and searching for users is constrained by these criteria:') }}
- </p>
- <p>
- <label for="ldap_userfilter_objectclass">
- {{ t('user_name', 'Only these object classes:') }}
- </label>
+ <fieldset class="ldap-wizard__users">
+ {{ t('user_name', 'Listing and searching for users is constrained by these criteria:') }}
- <select id="ldap_userfilter_objectclass"
- multiple="multiple"
- name="ldap_userfilter_objectclass"
- class="multiSelectPlugin" />
- </p>
- <p>
- <label />
- <span class="ldapInputColElement">{{ t('user_name', 'The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin.') }}</span>
- </p>
- <p>
- <label for="ldap_userfilter_groups">
- {{ t('user_name', 'Only from these groups:') }}
- </label>
+ <div class="ldap-wizard__users__line ldap-wizard__users__user-filter-object-class">
+ <NcSelect v-model="ldapConfig.ldapUserFilterObjectclass"
+ class="ldap-wizard__users__user-filter-object-class__select"
+ :disable="editUserFilter"
+ :options="['TODO']"
+ :input-label="t('user_name', 'Only these object classes:')"
+ :multiple="true" />
+ {{ t('user_name', 'The most common object classes for users are organizationalPerson, person, user, and inetOrgPerson. If you are not sure which object class to select, please consult your directory admin.') }}</span>
+ </div>
- <input type="text" class="ldapManyGroupsSupport ldapManyGroupsSearch hidden" placeholder="t('user_name', 'Search groups')">
+ <div class="ldap-wizard__users__line ldap-wizard__users__user-filter-groups">
+ <div>
+ {{ t('user_name', 'Only from these groups:') }}
+ </div>
- <select id="ldap_userfilter_groups"
- multiple="multiple"
- name="ldap_userfilter_groups"
- class="multiSelectPlugin" />
- </p>
+ <!-- <input type="text" class="ldapManyGroupsSupport ldapManyGroupsSearch hidden" > -->
+ <!-- <NcTextField :disable="editUserFilter"
+ :value.sync="ldapConfig.ldapUserFilterGroups"
+ :placeholder="t('user_name', 'Search groups')"
+ autocomplete="off" /> -->
+
+ <NcSelect v-model="ldapConfig.ldapUserFilterGroups"
+ class="ldap-wizard__users__user-filter-groups__select"
+ :options="['TODO']"
+ :disable="allowUserFilterGroupsSelection"
+ :input-label="t('user_name', 'Only these object classes:')"
+ :multiple="true" />
+ </div>
+
+ <!-- TODO -->
+ <div class="ldap-wizard__users__line">
<p class="ldapManyGroupsSupport hidden">
- <label />
<select class="ldapGroupList ldapGroupListAvailable"
multiple="multiple"
aria-describedby="ldapGroupListAvailable_instructions"
:title="t('user_name', 'Available groups')" />
- </p><p id="ldapGroupListAvailable_instructions" class="hidden-visually">
+ </p>
+ <p id="ldapGroupListAvailable_instructions" class="hidden-visually">
{{ t('user_name', 'Available groups') }}
</p>
- <span class="buttonSpan">
- <button class="ldapGroupListSelect" type="button">></button><br>
- <button class="ldapGroupListDeselect" type="button"><</button>
+
+ <span>
+ <NcButton class="ldapGroupListSelect">></NcButton>
+ <NcButton class="ldapGroupListDeselect"><</NcButton>
</span>
+
<select class="ldapGroupList ldapGroupListSelected"
multiple="multiple"
aria-describedby="ldapGroupListSelected_instructions"
:title="t('user_name', 'Selected groups')" />
+
<p id="ldapGroupListSelected_instructions" class="hidden-visually">
{{ t('user_name', 'Selected groups') }}
</p>
- <p>
- <label><a id="toggleRawUserFilter" class="ldapToggle">↓ {{ t('user_name', 'Edit LDAP Query') }}</a></label>
- </p>
- <p id="ldapReadOnlyUserFilterContainer" class="hidden ldapReadOnlyFilterContainer">
+ </div>
+
+ <div class="ldap-wizard__users__line ldap-wizard__users__user-filter">
+ <NcCheckboxRadioSwitch :checked.sync="editUserFilter">
+ {{ t('user_name', 'Edit LDAP Query') }}
+ </NcCheckboxRadioSwitch>
+
+ <div v-if="!editUserFilter">
<label>{{ t('user_name', 'LDAP Filter:') }}</label>
- <span class="ldapFilterReadOnlyElement ldapInputColElement" />
- </p>
- <p id="rawUserFilterContainer">
- <textarea id="ldap_userlist_filter"
- type="text"
- name="ldap_userlist_filter"
- class="ldapFilterInputElement"
- placeholder="t('user_name', 'Edit LDAP Query')"
- aria-describedby="ldap_userlist_filter_instructions"
- :title="t('user_name', 'The filter specifies which LDAP users shall have access to the %s instance.', { themeName: theme.getName()})" />
- </p>
- <p id="ldap_userlist_filter_instructions" class="hidden-visually">
- {{ t('user_name', 'The filter specifies which LDAP users shall have access to the %s instance.', { themeName: theme.getName()}) }}
- </p>
- <div class="ldapWizardInfo invisible">
-
+ <span>{{ ldapConfig.ldapUserListFilter }}</span>
</div>
- <p class="ldap_count">
- <NcButton class="ldapGetEntryCount ldapGetUserCount" name="ldapGetEntryCount" type="button">
- {{ t('user_name', 'Verify settings and count users') }}
- </NcButton>
- <span id="ldap_user_count" />
- </p>
- {{ wizardControls }}
+ <div v-else>
+ <NcTextArea :value.sync="ldapConfig.ldapUserListFilter"
+ :placeholder="t('user_name', 'Edit LDAP Query')"
+ :helper-text="t('user_name', 'The filter specifies which LDAP users shall have access to the {instanceName} instance.', { instanceName })" />
+ </div>
+ </div>
+
+ <div class="ldap-wizard__users__line ldap-wizard__users__user-count-check">
+ <NcButton @click="getUserCount">
+ {{ t('user_name', 'Verify settings and count users') }}
+ </NcButton>
+
+ <span v-if="userCount !== undefined">{{ t('user_ldap', "User count: {userCount}", { userCount }) }}</span>
</div>
</fieldset>
</template>
<script lang="ts" setup>
-import { defineProps, PropType } from 'vue'
+import { defineProps, computed, ref } from 'vue'
import { t } from '@nextcloud/l10n'
-import { NcButton } from '@nextcloud/vue'
+import { NcButton, NcTextArea, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'
+
+import { useLDAPConfigStore } from '../../store/config'
-import type { LDAPConfig } from '../../services/ldapConfigService'
+const ldapConfigStore = useLDAPConfigStore()
-const { ldapConfig } = defineProps({
- ldapConfig: {
- type: Object as PropType<LDAPConfig>,
+const { ldapConfigId } = defineProps({
+ ldapConfigId: {
+ type: String,
required: true,
},
})
-const wizardControls = ''
-const theme = {
- getName() {
- return 'TODO'
- },
+const ldapConfig = computed(() => ldapConfigStore.ldapConfigs[ldapConfigId])
+
+const userCount = ref<number>(-1)
+
+const editUserFilter = ref(false)
+const allowUserFilterGroupsSelection = ref(true) // TODO
+const instanceName = 'TODO'
+
+/**
+ *
+ */
+async function getUserCount() {
+ userCount.value++ // TODO: Implement
}
</script>
+<style lang="scss" scoped>
+.ldap-wizard__users {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+
+ &__line {
+ display: flex;
+ align-items: start;
+ }
+
+ &__user-filter-object-class {
+ display: flex;
+ gap: 16px;
+
+ &__select {
+ min-width: 50%;
+ flex-grow: 1;
+ }
+ }
+
+ &__user-filter-groups {
+ display: flex;
+ gap: 16px;
+
+ &__select {
+ min-width: 50%;
+ flex-grow: 1;
+ }
+ }
+
+ &__user-filter {
+ display: flex;
+ flex-direction: column;
+ }
+
+ &__user-count-check {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ }
+}
+</style>
--- /dev/null
+<!--
+ - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+ -->
+<template>
+ <div>
+ TODO: Wizard Controls: {{ ldapConfig.ldapHost }}
+ </div>
+</template>
+
+<script lang="ts" setup>
+import { defineProps, computed } from 'vue'
+
+import { useLDAPConfigStore } from '../store/config'
+
+const ldapConfigStore = useLDAPConfigStore()
+
+const { ldapConfigId } = defineProps({
+ ldapConfigId: {
+ type: String,
+ required: true,
+ },
+})
+
+const ldapConfig = computed(() => ldapConfigStore.ldapConfigs[ldapConfigId])
+</script>
+<style lang="scss" scoped>
+</style>
}),
actions: {
- async create(config: LDAPConfig) {
- const { configId, config: newConfig } = await createConfig(config)
- Vue.set(this.ldapConfigs, configId, newConfig)
+ async create() {
+ const { configId, config } = await createConfig({ ...this.defaultLdapConfig })
+ Vue.set(this.ldapConfigs, configId, config)
},
- async delete(configId: string) {
+ async copy(fromConfigId: string) {
+ const { configId, config } = await createConfig({ ...this.ldapConfigs[fromConfigId] })
+ Vue.set(this.ldapConfigs, configId, config)
+ },
+
+ async remove(configId: string) {
const result = await deleteConfig(configId)
if (result === true) {
Vue.delete(this.ldapConfigs, configId)
config = await updateConfig(configId, config)
Vue.set(this.ldapConfigs, configId, config)
},
+
+ async detectPort() {
+ // TODO
+ },
+
+ async detectBaseDN() {
+ // TODO
+ },
+
+ async testBaseDN() {
+ // TODO
+ },
},
})
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
- <form id="ldap" class="section">
+ <form class="ldap-wizard">
<h2>{{ t('user_ldap', 'LDAP/AD integration') }}</h2>
- <div class="ldap__config-selection">
+ <div class="ldap-wizard__config-selection">
<NcSelect v-model="selectedConfigId"
- :options="Object.values(ldapConfigStore.ldapConfigs)"
+ :options="selectOptions"
:input-label="t('user_ldap', 'Select LDAP Config')" />
<NcButton :label="t('user_ldap','Create New Config')" @click="ldapConfigStore.create">
<template #icon>
<NcLoadingIcon v-if="false" />
</div>
- <div v-if="selectedConfig !== undefined" id="ldapSettings">
- <div class="ldap__tab-selection">
- <NcCheckboxRadioSwitch v-for="(tabId, tabLabel) in tabs"
- :key="tabId"
- :button-variant="true"
- :checked.sync="selectedTab"
- :value="tabId"
- name="ldap_selected_tab"
- type="radio"
- button-variant-grouped="horizontal">
- {{ tabLabel }}
- </NcCheckboxRadioSwitch>
+ <div v-if="selectedConfigId !== undefined" class="ldap-wizard__tab-container">
+ <div class="ldap-wizard__tab-selection-container">
+ <div class="ldap-wizard__tab-selection">
+ <NcCheckboxRadioSwitch v-for="(tabLabel, tabId) in leftTabs"
+ :key="tabId"
+ :button-variant="true"
+ :checked.sync="selectedTab"
+ :value="tabId"
+ type="radio"
+ button-variant-grouped="horizontal">
+ {{ tabLabel }}
+ </NcCheckboxRadioSwitch>
+ </div>
+ <div class="ldap-wizard__tab-selection">
+ <NcCheckboxRadioSwitch v-for="(tabLabel, tabId) in rightTabs"
+ :key="tabId"
+ :button-variant="true"
+ :checked.sync="selectedTab"
+ :value="tabId"
+ type="radio"
+ button-variant-grouped="horizontal">
+ {{ tabLabel }}
+ </NcCheckboxRadioSwitch>
+ </div>
</div>
- <p v-if="!ldapModuleInstalled" class="ldapwarning">
+ <!-- TODO: change ldapwarning -->
+ <div v-if="!ldapModuleInstalled" class="ldapwarning">
{{ t('user_ldap', '<b>Warning:</b> The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it.') }}
- </p>
-
- <ServerTab v-if="selectedTab === 'server'" :ldap-config="selectedConfig" />
- <!-- <UsersTab v-else-if="selectedTab === 'users'" :ldap-config="selectedConfig" />
- <LoginTab v-else-if="selectedTab === 'login'" :ldap-config="selectedConfig" />
- <GroupsTab v-else-if="selectedTab === 'groups'" :ldap-config="selectedConfig" />
- <ExpertTab v-else-if="selectedTab === 'expert'" :ldap-config="selectedConfig" />
- <AdvancedTab v-else-if="selectedTab === 'advanced'" :ldap-config="selectedConfig" /> -->
+ </div>
+
+ <ServerTab v-if="selectedTab === 'server'" :ldap-config-id="selectedConfigId" />
+ <UsersTab v-else-if="selectedTab === 'users'" :ldap-config-id="selectedConfigId" />
+ <LoginTab v-else-if="selectedTab === 'login'" :ldap-config-id="selectedConfigId" />
+ <GroupsTab v-else-if="selectedTab === 'groups'" :ldap-config-id="selectedConfigId" />
+ <ExpertTab v-else-if="selectedTab === 'expert'" :ldap-config-id="selectedConfigId" />
+ <AdvancedTab v-else-if="selectedTab === 'advanced'" :ldap-config-id="selectedConfigId" />
+
+ <WizardControls class="ldap-wizard__controls" :ldap-config-id="selectedConfigId" />
</div>
</form>
</template>
<script lang="ts" setup>
-import { computed } from 'vue'
+import { ref } from 'vue'
+
import Plus from 'vue-material-design-icons/Plus.vue'
import { t } from '@nextcloud/l10n'
import { NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcButton } from '@nextcloud/vue'
import ServerTab from '../components/SettingsTabs/ServerTab.vue'
-// import UsersTab from '../components/SettingsTabs/UsersTab.vue'
-// import LoginTab from '../components/SettingsTabs/LoginTab.vue'
-// import GroupsTab from '../components/SettingsTabs/GroupsTab.vue'
-// import ExpertTab from '../components/SettingsTabs/ExpertTab.vue'
-// import AdvancedTab from '../components/SettingsTabs/AdvancedTab.vue'
+import UsersTab from '../components/SettingsTabs/UsersTab.vue'
+import LoginTab from '../components/SettingsTabs/LoginTab.vue'
+import GroupsTab from '../components/SettingsTabs/GroupsTab.vue'
+import ExpertTab from '../components/SettingsTabs/ExpertTab.vue'
+import AdvancedTab from '../components/SettingsTabs/AdvancedTab.vue'
+import WizardControls from '../components/WizardControls.vue'
import { useLDAPConfigStore } from '../store/config'
-const selectedTab = 'server'
-const selectedConfigId = null
-// TODO: Setup from initial state
-const ldapModuleInstalled = true
-
-const ldapConfigStore = useLDAPConfigStore()
-
-const selectedConfig = computed(() => ldapConfigStore.ldapConfigs[selectedConfigId ?? 0] ?? { ...ldapConfigStore.defaultLdapConfig })
-
-const tabs = {
+const leftTabs = {
server: t('user_ldap', 'Server'),
users: t('user_ldap', 'Users'),
login: t('user_ldap', 'Login Attributes'),
groups: t('user_ldap', 'Groups'),
+}
+
+const rightTabs = {
expert: t('user_ldap', 'Expert'),
advanced: t('user_ldap', 'Advanced'),
}
+
+const ldapConfigStore = useLDAPConfigStore()
+
+const selectedTab = ref('server')
+// eslint-disable-next-line prefer-const
+const selectedConfigId = ref(Object.keys(ldapConfigStore.ldapConfigs)[0] ?? undefined)
+// TODO: Setup from initial state
+const ldapModuleInstalled = true
+
+const selectOptions = Object.entries(ldapConfigStore.ldapConfigs).map(([configId, config]) => ({
+ id: configId,
+ label: `${configId}: ${config.ldapHost}`,
+}))
+
</script>
<style lang="scss" scoped>
-.ldap__config-selection {
- display: flex;
- align-items: center;
- gap: 16px;
-}
+.ldap-wizard {
+ padding: 16px;
+ max-width: 1000px;
+
+ &__config-selection {
+ display: flex;
+ align-items: bottom;
+ margin-bottom: 8px;
+ gap: 16px;
+ }
+
+ &__tab-selection-container {
+ display: flex;
+ justify-content: space-between;
+ }
+
+ &__tab-selection {
+ display: flex;
+ margin-left: -16px;
+ margin-bottom: 16px;
+
+ &:last-of-type {
+ margin-right: -16px;
+ }
+ }
+
+ &__tab-container {
+ border: 1px solid gray;
+ border-radius: var(--border-radius);
+ padding: 0 16px;
+ }
-.ldap__tab-selection {
- display: flex;
+ &__controls {
+ margin-top: 16px;
+ }
}
</style>