feat(ui): added teaser styling for CE EE-3780 (#7323)

* added teaser styling for CE
pull/7467/head
Richard Wei 2022-08-12 12:03:30 +12:00 committed by GitHub
parent 1fbaf5fcbf
commit a247db7e93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 529 additions and 434 deletions

View File

@ -886,6 +886,10 @@ json-tree .branch-preview {
text-decoration-line: underline; text-decoration-line: underline;
} }
reach-portal > div {
z-index: 10;
}
input[style*='background-image: url("data:image/png'] + [data-cy='auth-passwordInputToggle'] { input[style*='background-image: url("data:image/png'] + [data-cy='auth-passwordInputToggle'] {
right: 20px; right: 20px;
} }

View File

@ -86,7 +86,7 @@
--orange-1: #e86925; --orange-1: #e86925;
--BE-only: var(--orange-1); --BE-only: var(--ui-warning-7);
/* Default Theme */ /* Default Theme */
--bg-card-color: var(--white-color); --bg-card-color: var(--white-color);

4
app/assets/ico/lock.svg Normal file
View File

@ -0,0 +1,4 @@
<svg width="76" height="75" viewBox="0 0 76 75" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect opacity="0.2" x="0.5" width="75" height="75" rx="37.5" fill="#713B12"/>
<path d="M31.5353 36.1666V30.8333C31.5353 29.0652 32.2164 27.3695 33.4288 26.1192C34.6412 24.869 36.2855 24.1666 38 24.1666C39.7145 24.1666 41.3588 24.869 42.5712 26.1192C43.7835 27.3695 44.4646 29.0652 44.4646 30.8333V36.1666M28.9495 36.1666H47.0505C48.4786 36.1666 49.6364 37.3605 49.6364 38.8333V48.1666C49.6364 49.6394 48.4786 50.8333 47.0505 50.8333H28.9495C27.5214 50.8333 26.3636 49.6394 26.3636 48.1666V38.8333C26.3636 37.3605 27.5214 36.1666 28.9495 36.1666Z" stroke="#FEC84B" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 735 B

View File

@ -1,5 +1,5 @@
<a class="ml-5 vertical-center" href="{{ $ctrl.url }}" target="_blank" rel="noopener" ng-if="$ctrl.limitedToBE"> <a class="ml-5 vertical-center" href="{{ $ctrl.url }}" target="_blank" rel="noopener" ng-if="$ctrl.limitedToBE">
<ng-transclude></ng-transclude> <ng-transclude></ng-transclude>
<pr-icon icon="'briefcase'" feather="true" class="icon-primary"></pr-icon> <pr-icon icon="'briefcase'" feather="true" class-name="'icon icon-sm vertical-center'"></pr-icon>
<span class="be-indicator-label">Business Edition Feature</span> <span class="be-indicator-label">Business Edition Feature</span>
</a> </a>

View File

@ -20,14 +20,59 @@ button.limited-be.oauth-save-settings-button {
ng-form.limited-be, ng-form.limited-be,
form.limited-be, form.limited-be,
div.limited-be { div.limited-be {
border: solid 1px var(--BE-only); border: solid 2px var(--BE-only);
box-shadow: var(--shadow-boxselector-color); border-radius: 8px;
padding: 10px;
pointer-events: none; pointer-events: none;
touch-action: none; touch-action: none;
display: block; display: block;
} }
.limited-be-content {
background: rgba(247, 144, 9, 0.1);
opacity: 0.5;
padding: 10px;
}
.limited-be-link {
z-index: 5;
position: relative;
width: 270px;
height: 40px;
top: 0px;
right: 0px;
float: right;
border-top-right-radius: 8px;
border-bottom-left-radius: 8px;
background-color: var(--ui-warning-5);
color: var(--ui-warning-9);
padding: 5px 10px;
touch-action: auto;
cursor: hand;
pointer-events: auto;
}
.limited-be-link a {
cursor: hand;
pointer-events: auto;
color: var(--ui-warning-9);
}
.limited-be-link a:hover {
text-decoration: underline;
color: var(--ui-warning-9);
}
.overlay {
background-image: url(../../assets/ico/lock.svg);
background-repeat: no-repeat;
background-position: center;
}
.limited-be input,
.limited-be .widget-body {
background: rgba(247, 144, 9, 0.05);
}
.form-control.limited-be[disabled] { .form-control.limited-be[disabled] {
background-color: transparent !important; background-color: transparent !important;
} }

View File

@ -1,170 +1,176 @@
<ng-form class="ad-settings" limited-feature-dir="{{::$ctrl.limitedFeatureId}}" limited-feature-class="limited-be"> <ng-form class="ad-settings" limited-feature-dir="{{::$ctrl.limitedFeatureId}}" limited-feature-class="limited-be">
<be-feature-indicator feature="$ctrl.limitedFeatureId" class="my-8 block"></be-feature-indicator> <div class="overlay">
<div class="limited-be-link vertical-center"
><be-feature-indicator feature="$ctrl.limitedFeatureId"></be-feature-indicator
><portainer-tooltip message="'This feature is currently limited to Business Edition users only. '"></portainer-tooltip
></div>
<div class="limited-be-content">
<auto-user-provision-toggle ng-model="$ctrl.settings.AutoCreateUsers">
<field-description>
With automatic user provisioning enabled, Portainer will create user(s) automatically with standard user role and assign them to team(s) which matches to LDAP group
name(s). If disabled, users must be created in Portainer beforehand.
</field-description>
</auto-user-provision-toggle>
<auto-user-provision-toggle ng-model="$ctrl.settings.AutoCreateUsers"> <div>
<field-description> <div class="col-sm-12 form-section-title"> Information </div>
With automatic user provisioning enabled, Portainer will create user(s) automatically with standard user role and assign them to team(s) which matches to LDAP group name(s). <div class="form-group col-sm-12 text-muted small">
If disabled, users must be created in Portainer beforehand. When using Microsoft AD authentication, Portainer will delegate user authentication to the Domain Controller(s) configured below; if there is no connectivity, Portainer
</field-description> will fallback to internal authentication.
</auto-user-provision-toggle> </div>
<div>
<div class="col-sm-12 form-section-title"> Information </div>
<div class="form-group col-sm-12 text-muted small">
When using Microsoft AD authentication, Portainer will delegate user authentication to the Domain Controller(s) configured below; if there is no connectivity, Portainer will
fallback to internal authentication.
</div>
</div>
<div class="col-sm-12 form-section-title"> AD configuration </div>
<div class="form-group">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
You can configure multiple AD Controllers for authentication fallback. Make sure all servers are using the same configuration (i.e. if TLS is enabled, they should all use
the same certificates).
</p>
</div>
</div>
<div class="form-group">
<label for="ldap_url" class="col-sm-3 col-lg-2 control-label text-left" style="display: flex; flex-wrap: wrap">
AD Controller
<button
type="button"
class="label label-default interactive vertical-center"
style="border: 0"
ng-click="$ctrl.addLDAPUrl()"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'plus-circle'" feather="true"></pr-icon>
Add additional server
</button>
</label>
<div class="col-sm-9 col-lg-10">
<div ng-repeat="url in $ctrl.settings.URLs track by $index" style="display: flex; margin-bottom: 10px">
<input
type="text"
class="form-control"
id="ldap_url"
ng-model="$ctrl.settings.URLs[$index]"
placeholder="e.g. 10.0.0.10:389 or myldap.domain.tld:389"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
<button
ng-if="$index > 0"
class="btn btn-sm btn-danger"
type="button"
ng-click="$ctrl.removeLDAPUrl($index)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'trash-2'" feather="true"></pr-icon>
</button>
</div> </div>
<div class="col-sm-12 form-section-title"> AD configuration </div>
<div class="form-group">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
You can configure multiple AD Controllers for authentication fallback. Make sure all servers are using the same configuration (i.e. if TLS is enabled, they should all
use the same certificates).
</p>
</div>
</div>
<div class="form-group">
<label for="ldap_url" class="col-sm-3 col-lg-2 control-label text-left" style="display: flex; flex-wrap: wrap">
AD Controller
<button
type="button"
class="label label-default interactive vertical-center"
style="border: 0"
ng-click="$ctrl.addLDAPUrl()"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'plus-circle'" feather="true"></pr-icon>
Add additional server
</button>
</label>
<div class="col-sm-9 col-lg-10">
<div ng-repeat="url in $ctrl.settings.URLs track by $index" style="display: flex; margin-bottom: 10px">
<input
type="text"
class="form-control"
id="ldap_url"
ng-model="$ctrl.settings.URLs[$index]"
placeholder="e.g. 10.0.0.10:389 or myldap.domain.tld:389"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
<button
ng-if="$index > 0"
class="btn btn-sm btn-danger"
type="button"
ng-click="$ctrl.removeLDAPUrl($index)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'trash-2'" feather="true"></pr-icon>
</button>
</div>
</div>
</div>
<div class="form-group">
<label for="ldap_username" class="col-sm-3 control-label text-left">
Service Account
<portainer-tooltip message="'Account that will be used to search for users.'"></portainer-tooltip>
</label>
<div class="col-sm-9">
<input
type="text"
class="form-control"
id="ldap_username"
ng-model="$ctrl.settings.ReaderDN"
placeholder="reader@domain.tld"
ng-change="$ctrl.onAccountChange($ctrl.settings.ReaderDN)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<div class="form-group">
<label for="ldap_password" class="col-sm-3 control-label text-left">
Service Account Password
<portainer-tooltip message="'If you do not enter a password, Portainer will leave the current password unchanged.'"></portainer-tooltip>
</label>
<div class="col-sm-9">
<input
type="password"
class="form-control"
id="ldap_password"
ng-model="$ctrl.settings.Password"
placeholder="password"
autocomplete="new-password"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<ldap-connectivity-check
ng-if="!$ctrl.settings.TLSConfig.TLS && !$ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-settings-security
title="AD Connectivity Security"
settings="$ctrl.settings"
tlsca-cert="$ctrl.tlscaCert"
upload-in-progress="$ctrl.state.uploadInProgress"
on-tlsca-cert-change="($ctrl.onTlscaCertChange)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-settings-security>
<ldap-connectivity-check
ng-if="$ctrl.settings.TLSConfig.TLS || $ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-user-search
style="margin-top: 5px"
show-username-format="true"
settings="$ctrl.settings.SearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=user)"
on-search-click="($ctrl.searchUsers)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-user-search>
<ldap-group-search
style="margin-top: 5px"
settings="$ctrl.settings.GroupSearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=group)"
on-search-click="($ctrl.searchGroups)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-group-search>
<ldap-custom-admin-group
style="margin-top: 5px"
settings="$ctrl.settings"
on-search-click="($ctrl.onSearchAdminGroupsClick)"
selected-admin-groups="$ctrl.selectedAdminGroups"
default-admin-group-search-filter="'(objectClass=groupOfNames)'"
limited-feature-id="$ctrl.limitedFeatureId"
is-limited-feature-self-contained="false"
></ldap-custom-admin-group>
<ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId" is-limited-feature-self-contained="false"></ldap-settings-test-login>
<save-auth-settings-button
on-save-settings="($ctrl.onSaveSettings)"
save-button-state="($ctrl.saveButtonState)"
limited-feature-id="$ctrl.limitedFeatureId"
save-button-disabled="($ctrl.isSaveSettingButtonDisabled())"
></save-auth-settings-button>
</div> </div>
</div> </div>
<div class="form-group">
<label for="ldap_username" class="col-sm-3 control-label text-left">
Service Account
<portainer-tooltip message="'Account that will be used to search for users.'"></portainer-tooltip>
</label>
<div class="col-sm-9">
<input
type="text"
class="form-control"
id="ldap_username"
ng-model="$ctrl.settings.ReaderDN"
placeholder="reader@domain.tld"
ng-change="$ctrl.onAccountChange($ctrl.settings.ReaderDN)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<div class="form-group">
<label for="ldap_password" class="col-sm-3 control-label text-left">
Service Account Password
<portainer-tooltip message="'If you do not enter a password, Portainer will leave the current password unchanged.'"></portainer-tooltip>
</label>
<div class="col-sm-9">
<input
type="password"
class="form-control"
id="ldap_password"
ng-model="$ctrl.settings.Password"
placeholder="password"
autocomplete="new-password"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<ldap-connectivity-check
ng-if="!$ctrl.settings.TLSConfig.TLS && !$ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-settings-security
title="AD Connectivity Security"
settings="$ctrl.settings"
tlsca-cert="$ctrl.tlscaCert"
upload-in-progress="$ctrl.state.uploadInProgress"
on-tlsca-cert-change="($ctrl.onTlscaCertChange)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-settings-security>
<ldap-connectivity-check
ng-if="$ctrl.settings.TLSConfig.TLS || $ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-user-search
style="margin-top: 5px"
show-username-format="true"
settings="$ctrl.settings.SearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=user)"
on-search-click="($ctrl.searchUsers)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-user-search>
<ldap-group-search
style="margin-top: 5px"
settings="$ctrl.settings.GroupSearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=group)"
on-search-click="($ctrl.searchGroups)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-group-search>
<ldap-custom-admin-group
style="margin-top: 5px"
settings="$ctrl.settings"
on-search-click="($ctrl.onSearchAdminGroupsClick)"
selected-admin-groups="$ctrl.selectedAdminGroups"
default-admin-group-search-filter="'(objectClass=groupOfNames)'"
limited-feature-id="$ctrl.limitedFeatureId"
is-limited-feature-self-contained="false"
></ldap-custom-admin-group>
<ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId" is-limited-feature-self-contained="false"></ldap-settings-test-login>
<save-auth-settings-button
on-save-settings="($ctrl.onSaveSettings)"
save-button-state="($ctrl.saveButtonState)"
limited-feature-id="$ctrl.limitedFeatureId"
save-button-disabled="($ctrl.isSaveSettingButtonDisabled())"
></save-auth-settings-button>
</ng-form> </ng-form>

View File

@ -1,184 +1,192 @@
<ng-form limited-feature-dir="{{::$ctrl.limitedFeatureId}}" limited-feature-class="limited-be" class="ldap-settings-openldap"> <ng-form limited-feature-dir="{{::$ctrl.limitedFeatureId}}" limited-feature-class="limited-be" class="ldap-settings-openldap">
<be-feature-indicator feature="$ctrl.limitedFeatureId"></be-feature-indicator> <div class="overlay">
<div class="limited-be-link vertical-center"
<div> ><be-feature-indicator feature="$ctrl.limitedFeatureId"></be-feature-indicator
<div class="col-sm-12 form-section-title"> Information </div> ><portainer-tooltip message="'This feature is currently limited to Business Edition users only. '"></portainer-tooltip
<div class="form-group col-sm-12 text-muted small"> ></div>
When using LDAP authentication, Portainer will delegate user authentication to a LDAP server and fallback to internal authentication if LDAP authentication fails. <div class="limited-be-content">
</div> <div>
</div> <div class="col-sm-12 form-section-title"> Information </div>
<div class="form-group col-sm-12 text-muted small">
<div class="col-sm-12 form-section-title"> LDAP configuration </div> When using LDAP authentication, Portainer will delegate user authentication to a LDAP server and fallback to internal authentication if LDAP authentication fails.
</div>
<div class="form-group">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
You can configure multiple LDAP Servers for authentication fallback. Make sure all servers are using the same configuration (i.e. if TLS is enabled, they should all use the
same certificates).
</p>
</div>
</div>
<div class="form-group">
<label for="ldap_url" class="col-sm-3 col-lg-2 control-label text-left" style="display: flex; flex-wrap: wrap">
LDAP Server
<button
type="button"
class="label label-default interactive vertical-center"
style="border: 0"
ng-click="$ctrl.addLDAPUrl()"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'plus-circle'" feather="true"></pr-icon>
Add additional server
</button>
</label>
<div class="col-sm-9 col-lg-10">
<div ng-repeat="url in $ctrl.settings.URLs track by $index" style="display: flex; margin-bottom: 10px">
<input
type="text"
class="form-control"
id="ldap_url"
ng-model="$ctrl.settings.URLs[$index]"
placeholder="e.g. 10.0.0.10:389 or myldap.domain.tld:389"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
<button
ng-if="$index > 0"
class="btn btn-sm btn-danger"
type="button"
ng-click="$ctrl.removeLDAPUrl($index)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'trash-2'" feather="true" size="'md'"></pr-icon>
</button>
</div> </div>
</div>
</div>
<!-- Anonymous mode--> <div class="col-sm-12 form-section-title"> LDAP configuration </div>
<div class="form-group">
<label for="anonymous_mode" class="control-label text-left col-sm-3 col-lg-2">
Anonymous mode
<portainer-tooltip message="'Enable this option if the server is configured for Anonymous access.'"></portainer-tooltip>
</label>
<div class="col-sm-9 col-lg-10"> <div class="form-group">
<label class="switch"> <div class="col-sm-12 small text-muted">
<input type="checkbox" id="anonymous_mode" ng-model="$ctrl.settings.AnonymousMode" limited-feature-dir="{{::$ctrl.limitedFeatureId}}" limited-feature-tabindex="-1" /> <p class="vertical-center">
<span class="slider round"></span> <pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
</label> You can configure multiple LDAP Servers for authentication fallback. Make sure all servers are using the same configuration (i.e. if TLS is enabled, they should all use
</div> the same certificates).
</div> </p>
<!-- !Anonymous mode--> </div>
<div ng-if="!$ctrl.settings.AnonymousMode">
<div class="form-group">
<label for="ldap_username" class="col-sm-3 col-lg-2 control-label text-left">
Reader DN
<portainer-tooltip message="'Account that will be used to search for users.'"></portainer-tooltip>
</label>
<div class="col-sm-9 col-lg-10">
<input
type="text"
class="form-control"
id="ldap_username"
ng-model="$ctrl.settings.ReaderDN"
placeholder="cn=user,dc=domain,dc=tld"
ng-change="$ctrl.onAccountChange($ctrl.settings.ReaderDN)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div> </div>
</div>
<div class="form-group"> <div class="form-group">
<label for="ldap_password" class="col-sm-3 col-lg-2 control-label text-left"> <label for="ldap_url" class="col-sm-3 col-lg-2 control-label text-left" style="display: flex; flex-wrap: wrap">
Password LDAP Server
<portainer-tooltip message="'If you do not enter a password, Portainer will leave the current password unchanged.'"></portainer-tooltip> <button
</label> type="button"
<div class="col-sm-9"> class="label label-default interactive vertical-center"
<input style="border: 0"
type="password" ng-click="$ctrl.addLDAPUrl()"
class="form-control" limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
id="ldap_password" limited-feature-tabindex="-1"
ng-model="$ctrl.settings.Password" >
placeholder="password" <pr-icon icon="'plus-circle'" feather="true"></pr-icon>
autocomplete="new-password" Add additional server
limited-feature-dir="{{::$ctrl.limitedFeatureId}}" </button>
limited-feature-tabindex="-1" </label>
/> <div class="col-sm-9 col-lg-10">
<div ng-repeat="url in $ctrl.settings.URLs track by $index" style="display: flex; margin-bottom: 10px">
<input
type="text"
class="form-control"
id="ldap_url"
ng-model="$ctrl.settings.URLs[$index]"
placeholder="e.g. 10.0.0.10:389 or myldap.domain.tld:389"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
<button
ng-if="$index > 0"
class="btn btn-sm btn-danger"
type="button"
ng-click="$ctrl.removeLDAPUrl($index)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
>
<pr-icon icon="'trash-2'" feather="true" size="'md'"></pr-icon>
</button>
</div>
</div>
</div> </div>
<!-- Anonymous mode-->
<div class="form-group">
<div class="col-sm-12">
<label for="anonymous_mode" class="control-label text-left col-sm-3 col-lg-2">
Anonymous mode
<portainer-tooltip message="'Enable this option if the server is configured for Anonymous access.'"></portainer-tooltip>
</label>
<div class="col-sm-9 col-lg-10">
<label class="switch">
<input type="checkbox" id="anonymous_mode" ng-model="$ctrl.settings.AnonymousMode" limited-feature-dir="{{::$ctrl.limitedFeatureId}}" limited-feature-tabindex="-1" />
<span class="slider round"></span>
</label>
</div>
</div>
</div>
<!-- !Anonymous mode-->
<div ng-if="!$ctrl.settings.AnonymousMode">
<div class="form-group">
<label for="ldap_username" class="col-sm-3 col-lg-2 control-label text-left">
Reader DN
<portainer-tooltip message="'Account that will be used to search for users.'"></portainer-tooltip>
</label>
<div class="col-sm-9 col-lg-10">
<input
type="text"
class="form-control"
id="ldap_username"
ng-model="$ctrl.settings.ReaderDN"
placeholder="cn=user,dc=domain,dc=tld"
ng-change="$ctrl.onAccountChange($ctrl.settings.ReaderDN)"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<div class="form-group">
<label for="ldap_password" class="col-sm-3 col-lg-2 control-label text-left">
Password
<portainer-tooltip message="'If you do not enter a password, Portainer will leave the current password unchanged.'"></portainer-tooltip>
</label>
<div class="col-sm-9">
<input
type="password"
class="form-control"
id="ldap_password"
ng-model="$ctrl.settings.Password"
placeholder="password"
autocomplete="new-password"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
</div>
<div class="form-group" ng-if="$ctrl.settings.AnonymousMode">
<label for="ldap_domain_root" class="col-sm-3 col-lg-2 control-label text-left"> Domain root </label>
<div class="col-sm-9">
<input
type="text"
class="form-control"
id="ldap_domain_root"
ng-model="$ctrl.domainSuffix"
placeholder="dc=domain,dc=tld"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<ldap-connectivity-check
ng-if="!$ctrl.settings.TLSConfig.TLS && !$ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-settings-security
title="Connectivity Security"
settings="$ctrl.settings"
tlsca-cert="$ctrl.tlscaCert"
upload-in-progress="$ctrl.state.uploadInProgress"
on-tlsca-cert-change="($ctrl.onTlscaCertChange)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-settings-security>
<ldap-connectivity-check
ng-if="$ctrl.settings.TLSConfig.TLS || $ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-user-search
style="margin-top: 5px"
settings="$ctrl.settings.SearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=inetOrgPerson)"
on-search-click="($ctrl.onSearchUsersClick)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-user-search>
<ldap-group-search
style="margin-top: 5px"
settings="$ctrl.settings.GroupSearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=groupOfNames)"
on-search-click="($ctrl.onSearchGroupsClick)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-group-search>
<ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId"></ldap-settings-test-login>
<save-auth-settings-button
on-save-settings="($ctrl.onSaveSettings)"
save-button-state="($ctrl.saveButtonState)"
save-button-disabled="!$ctrl.saveButtonDisabled()"
limited-feature-id="$ctrl.limitedFeatureId"
></save-auth-settings-button>
</div> </div>
</div> </div>
<div class="form-group" ng-if="$ctrl.settings.AnonymousMode">
<label for="ldap_domain_root" class="col-sm-3 col-lg-2 control-label text-left"> Domain root </label>
<div class="col-sm-9">
<input
type="text"
class="form-control"
id="ldap_domain_root"
ng-model="$ctrl.domainSuffix"
placeholder="dc=domain,dc=tld"
limited-feature-dir="{{::$ctrl.limitedFeatureId}}"
limited-feature-tabindex="-1"
/>
</div>
</div>
<ldap-connectivity-check
ng-if="!$ctrl.settings.TLSConfig.TLS && !$ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-settings-security
title="Connectivity Security"
settings="$ctrl.settings"
tlsca-cert="$ctrl.tlscaCert"
upload-in-progress="$ctrl.state.uploadInProgress"
on-tlsca-cert-change="($ctrl.onTlscaCertChange)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-settings-security>
<ldap-connectivity-check
ng-if="$ctrl.settings.TLSConfig.TLS || $ctrl.settings.StartTLS"
settings="$ctrl.settings"
state="$ctrl.state"
connectivity-check="$ctrl.connectivityCheck"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-connectivity-check>
<ldap-user-search
style="margin-top: 5px"
settings="$ctrl.settings.SearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=inetOrgPerson)"
on-search-click="($ctrl.onSearchUsersClick)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-user-search>
<ldap-group-search
style="margin-top: 5px"
settings="$ctrl.settings.GroupSearchSettings"
domain-suffix="{{ $ctrl.domainSuffix }}"
base-filter="(objectClass=groupOfNames)"
on-search-click="($ctrl.onSearchGroupsClick)"
limited-feature-id="$ctrl.limitedFeatureId"
></ldap-group-search>
<ldap-settings-test-login settings="$ctrl.settings" limited-feature-id="$ctrl.limitedFeatureId"></ldap-settings-test-login>
<save-auth-settings-button
on-save-settings="($ctrl.onSaveSettings)"
save-button-state="($ctrl.saveButtonState)"
save-button-disabled="!$ctrl.saveButtonDisabled()"
limited-feature-id="$ctrl.limitedFeatureId"
></save-auth-settings-button>
</ng-form> </ng-form>

View File

@ -1,46 +1,61 @@
<page-header title="'User Activity'" breadcrumbs="['Activity Logs']" reload="true"> </page-header> <page-header title="'User Activity'" breadcrumbs="['Activity Logs']" reload="true"> </page-header>
<div class="be-indicator-container"> <div class="be-indicator-container limited-be">
<rd-widget> <div class="overlay">
<rd-widget-body> <div class="limited-be-link vertical-center"
<div class="form-horizontal"> ><be-feature-indicator feature="$ctrl.limitedFeature"></be-feature-indicator
<div class="form-group"> ><portainer-tooltip message="'This feature is currently limited to Business Edition users only. '"></portainer-tooltip
<label for="dateRangeInput" class="col-sm-2 control-label text-left">Date Range</label> ></div>
<div class="col-sm-6"> <div class="limited-be-content">
<input type="text" class="form-control" disabled /> <rd-widget>
<rd-widget-body>
<div class="form-horizontal">
<div class="form-group">
<label for="dateRangeInput" class="col-sm-2 control-label text-left">Date Range</label>
<div class="col-sm-6">
<input type="text" class="form-control" disabled />
</div>
</div>
</div> </div>
</div> <p class="text-muted small vertical-center">
</div> <pr-icon icon="'info'" feather="true" class-name="'icon icon-sm icon-primary'"></pr-icon>
<p class="text-muted small vertical-center"> Portainer user activity logs have a maximum retention of 7 days.
<pr-icon icon="'info'" feather="true" class-name="'icon icon-sm icon-primary'"></pr-icon> </p>
Portainer user activity logs have a maximum retention of 7 days. <div>
</p> <button type="button" class="btn btn-sm btn-primary" limited-feature-dir="{{::$ctrl.limitedFeature}}" limited-feature-class="limited-be" limited-feature-disabled>
<div> <pr-icon icon="'download'" feather="true" icon-class="'icon icon-sm'"></pr-icon>
<button type="button" class="btn btn-sm btn-primary" limited-feature-dir="{{::$ctrl.limitedFeature}}" limited-feature-class="limited-be" limited-feature-disabled> Export as CSV
<pr-icon icon="'download'" feather="true" icon-class="'icon icon-sm'"></pr-icon> </button>
Export as CSV </div>
</button> </rd-widget-body>
<be-feature-indicator feature="$ctrl.limitedFeature"></be-feature-indicator> </rd-widget>
</div> </div>
</rd-widget-body> </div>
</rd-widget> </div>
</div>
<div class="be-indicator-container limited-be">
<div class="be-indicator-container"> <div class="overlay">
<div class="row"> <div class="limited-be-link vertical-center"
<activity-logs-datatable ><be-feature-indicator feature="$ctrl.limitedFeature"></be-feature-indicator
logs="$ctrl.state.logs" ><portainer-tooltip message="'This feature is currently limited to Business Edition users only. '"></portainer-tooltip
keyword="$ctrl.state.keyword" ></div>
sort="$ctrl.state.sort" <div class="limited-be-content">
limit="$ctrl.state.limit" <div class="row">
context-filter="$ctrl.state.contextFilter" <activity-logs-datatable
total-items="$ctrl.state.totalItems" logs="$ctrl.state.logs"
current-page="$ctrl.state.currentPage" keyword="$ctrl.state.keyword"
feature="{{:: $ctrl.limitedFeature}}" sort="$ctrl.state.sort"
on-change-keyword="($ctrl.onChangeKeyword)" limit="$ctrl.state.limit"
on-change-sort="($ctrl.onChangeSort)" context-filter="$ctrl.state.contextFilter"
on-change-limit="($ctrl.onChangeLimit)" total-items="$ctrl.state.totalItems"
on-change-page="($ctrl.onChangePage)" current-page="$ctrl.state.currentPage"
></activity-logs-datatable> feature="{{:: $ctrl.limitedFeature}}"
on-change-keyword="($ctrl.onChangeKeyword)"
on-change-sort="($ctrl.onChangeSort)"
on-change-limit="($ctrl.onChangeLimit)"
on-change-page="($ctrl.onChangePage)"
></activity-logs-datatable>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -11,7 +11,7 @@
<be-feature-indicator feature="{{::$ctrl.feature}}"></be-feature-indicator> <be-feature-indicator feature="{{::$ctrl.feature}}"></be-feature-indicator>
</div> </div>
<div class="vertical-center"> <div class="vertical-center">
<datatable-searchbar on-change="($ctrl.onChangeKeyword)" value="$ctrl.keyword"></datatable-searchbar> <datatable-searchbar on-change="($ctrl.onChangeKeyword)"></datatable-searchbar>
</div> </div>
</div> </div>
<div class="table-responsive"> <div class="table-responsive">

View File

@ -1,48 +1,63 @@
<page-header title="'User Activity'" breadcrumbs="['User authentication activity']" reload="true"> </page-header> <page-header title="'User Activity'" breadcrumbs="['User authentication activity']" reload="true"> </page-header>
<div class="be-indicator-container"> <div class="be-indicator-container limited-be">
<rd-widget> <div class="overlay">
<rd-widget-body> <div class="limited-be-link vertical-center"
<div class="form-horizontal"> ><be-feature-indicator feature="$ctrl.limitedFeature"></be-feature-indicator
<div class="form-group"> ><portainer-tooltip message="'This feature is currently limited to Business Edition users only. '"></portainer-tooltip
<label for="dateRangeInput" class="col-sm-2 control-label text-left">Date Range</label> ></div>
<div class="col-sm-6"> <div class="limited-be-content">
<input type="text" class="form-control" disabled /> <rd-widget>
<rd-widget-body>
<div class="form-horizontal">
<div class="form-group">
<label for="dateRangeInput" class="col-sm-2 control-label text-left">Date Range</label>
<div class="col-sm-6">
<input type="text" class="form-control" disabled />
</div>
</div>
</div> </div>
</div> <p class="text-muted small vertical-center">
</div> <pr-icon icon="'info'" feather="true" class-name="'icon icon-sm icon-primary'"></pr-icon>
<p class="text-muted small vertical-center"> Portainer user authentication activity logs have a maximum retention of 7 days.
<pr-icon icon="'info'" feather="true" class-name="'icon icon-sm icon-primary'"></pr-icon> </p>
Portainer user authentication activity logs have a maximum retention of 7 days. <div>
</p> <button type="button" class="btn btn-sm btn-primary" limited-feature-dir="{{::$ctrl.limitedFeature}}" limited-feature-class="limited-be" limited-feature-disabled
<div> ><pr-icon icon="'download'" feather="true" icon-class="'icon icon-sm'"></pr-icon>Export as CSV
<button type="button" class="btn btn-sm btn-primary" limited-feature-dir="{{::$ctrl.limitedFeature}}" limited-feature-class="limited-be" limited-feature-disabled </button>
><pr-icon icon="'download'" feather="true" icon-class="'icon icon-sm'"></pr-icon>Export as CSV </div>
</button> </rd-widget-body>
<be-feature-indicator feature="$ctrl.limitedFeature"></be-feature-indicator> </rd-widget>
</div> </div>
</rd-widget-body> </div>
</rd-widget> </div>
</div>
<div class="be-indicator-container limited-be">
<div class="be-indicator-container"> <div class="overlay">
<div class="row"> <div class="limited-be-link vertical-center"
<auth-logs-datatable ><be-feature-indicator feature="$ctrl.limitedFeature"></be-feature-indicator
logs="$ctrl.state.logs" ><portainer-tooltip message="'This feature is currently limited to Business Edition users only. '"></portainer-tooltip
keyword="$ctrl.state.keyword" ></div>
sort="$ctrl.state.sort" <div class="limited-be-content">
limit="$ctrl.state.limit" <div class="row">
context-filter="$ctrl.state.contextFilter" <auth-logs-datatable
type-filter="$ctrl.state.typeFilter" logs="$ctrl.state.logs"
total-items="$ctrl.state.totalItems" keyword="$ctrl.state.keyword"
current-page="$ctrl.state.currentPage" sort="$ctrl.state.sort"
feature="{{:: $ctrl.limitedFeature}}" limit="$ctrl.state.limit"
on-change-context-filter="($ctrl.onChangeContextFilter)" context-filter="$ctrl.state.contextFilter"
on-change-type-filter="($ctrl.onChangeTypeFilter)" type-filter="$ctrl.state.typeFilter"
on-change-keyword="($ctrl.onChangeKeyword)" total-items="$ctrl.state.totalItems"
on-change-sort="($ctrl.onChangeSort)" current-page="$ctrl.state.currentPage"
on-change-limit="($ctrl.onChangeLimit)" feature="{{:: $ctrl.limitedFeature}}"
on-change-page="($ctrl.onChangePage)" on-change-context-filter="($ctrl.onChangeContextFilter)"
></auth-logs-datatable> on-change-type-filter="($ctrl.onChangeTypeFilter)"
on-change-keyword="($ctrl.onChangeKeyword)"
on-change-sort="($ctrl.onChangeSort)"
on-change-limit="($ctrl.onChangeLimit)"
on-change-page="($ctrl.onChangePage)"
></auth-logs-datatable>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,6 @@
import { PropsWithChildren } from 'react'; import { PropsWithChildren } from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import { Briefcase } from 'react-feather';
import './BEFeatureIndicator.css'; import './BEFeatureIndicator.css';
@ -24,19 +25,16 @@ export function BEFeatureIndicator({
if (!limitedToBE) { if (!limitedToBE) {
return null; return null;
} }
return ( return (
<a <a
className={clsx('be-indicator', className)} className={clsx('be-indicator vertical-center', className)}
href={url} href={url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
{children} {children}
{showIcon && ( {showIcon && <Briefcase className="icon icon-sm vertical-center" />}
<i className="fas fa-briefcase space-right be-indicator-icon" /> <span className="be-indicator-label break-words space-left">
)}
<span className="be-indicator-label break-words">
Business Edition Feature Business Edition Feature
</span> </span>
</a> </a>