fix(ui): kubernetes-consistent-styling EE-3820 (#7425)

pull/7471/head
Ali 2022-08-13 00:22:45 +06:00 committed by GitHub
parent b67f404d8d
commit 36c93c7f57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 713 additions and 548 deletions

View File

@ -881,3 +881,7 @@ input[style*='background-image: url("data:image/png'] + [data-cy='auth-passwordI
input[style*='background-image: url("data:image/png'] {
padding-right: 60px;
}
.web-editor .trancluded-item:empty {
display: none;
}

View File

@ -98,7 +98,8 @@ fieldset[disabled] .btn {
background-color: var(--ui-gray-3);
}
.hyperlink {
.hyperlink,
.hyperlink:focus {
color: var(--ui-blue-8);
}

View File

@ -210,6 +210,7 @@ code {
pre {
border: 1px solid var(--border-pre-color);
border-radius: 8px;
background-color: var(--bg-pre-color);
color: var(--text-pre-color);
}
@ -394,6 +395,10 @@ input:-webkit-autofill {
/* Overide Vendor CSS */
.btn-link:hover {
color: var(--text-link-hover-color) !important;
}
.multiSelect.inlineBlock button {
margin: 0;
}
@ -425,3 +430,23 @@ input:-webkit-autofill {
background-color: var(--bg-nav-tabs-active-color);
border-top-right-radius: 8px;
}
/* Code Script Style */
.code-script {
background-color: var(--bg-code-script-color);
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
padding: 5px;
}
.nav-container {
border: 1px solid var(--border-nav-container-color);
background-color: var(--bg-nav-container-color);
border-radius: 8px;
padding: 10px;
}
.nav-tabs > li {
background-color: var(--bg-nav-tabs-active-color);
border-top-right-radius: 8px;
}

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="auto" height="auto" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-book"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="auto" height="auto" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-book"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg><svg width="auto" height="auto" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M58.3333 9.45654V26.6671C58.3333 29.0007 58.3333 30.1675 58.7875 31.0588C59.1869 31.8428 59.8244 32.4802 60.6084 32.8797C61.4997 33.3338 62.6665 33.3338 65 33.3338H82.2106M58.3333 72.9168L68.75 62.5002L58.3333 52.0835M41.6667 52.0835L31.25 62.5002L41.6667 72.9168M83.3333 41.6178V71.6668C83.3333 78.6675 83.3333 82.1678 81.9709 84.8417C80.7725 87.1937 78.8602 89.106 76.5082 90.3044C73.8343 91.6668 70.334 91.6668 63.3333 91.6668H36.6667C29.666 91.6668 26.1657 91.6668 23.4918 90.3044C21.1398 89.106 19.2275 87.1937 18.0291 84.8417C16.6667 82.1678 16.6667 78.6675 16.6667 71.6668V28.3335C16.6667 21.3328 16.6667 17.8325 18.0291 15.1586C19.2275 12.8066 21.1398 10.8943 23.4918 9.69591C26.1657 8.3335 29.666 8.3335 36.6667 8.3335H50.0491C53.1064 8.3335 54.6351 8.3335 56.0737 8.67887C57.3492 8.98508 58.5685 9.49014 59.6869 10.1755C60.9484 10.9485 62.0293 12.0295 64.1912 14.1914L77.4755 27.4756C79.6374 29.6375 80.7183 30.7185 81.4913 31.9799C82.1767 33.0983 82.6818 34.3176 82.988 35.5931C83.3333 37.0317 83.3333 38.5604 83.3333 41.6178Z" stroke="currentColor" stroke-width="8.2" stroke-linecap="round" stroke-linejoin="round"/> </svg>

Before

Width:  |  Height:  |  Size: 349 B

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -58,10 +58,11 @@
<!-- ! don't use registry -->
<!-- info message -->
<div class="form-group" ng-show="$ctrl.form.image_name.$invalid">
<div class="col-sm-12 small">
<div ng-messages="$ctrl.form.image_name.$error">
<p ng-message="required">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Image name is required.
<div class="small">
<div class="col-sm-3 col-lg-2"></div>
<div class="col-sm-8" ng-messages="$ctrl.form.image_name.$error">
<p class="text-muted vertical-center" ng-message="required">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true" class="vertical-center"></pr-icon> Image name is required.
<span ng-if="$ctrl.canPull">Tag must be specified otherwise Portainer will pull all tags associated to the image.</span>
</p>
</div>

View File

@ -6,7 +6,6 @@
<div class="widget-icon space-right">
<pr-icon icon="'server'" feather="true"></pr-icon>
</div>
<span>
{{ $ctrl.titleText }}
</span>
@ -162,15 +161,19 @@
<a
ng-if="item.Status === 'Running' && $ctrl.useServerMetrics"
ui-sref="kubernetes.applications.application.stats({ pod: item.PodName, container: item.Name })"
style="margin-right: 10px"
class="vertical-center mr-1"
>
<pr-icon icon="'pie-chart'" class="mr-1" feather="true"></pr-icon>Stats
<pr-icon icon="'bar-chart'" feather="true"></pr-icon>Stats
</a>
<a ui-sref="kubernetes.applications.application.logs({ pod: item.PodName, container: item.Name })">
<pr-icon icon="'file-text'" class="mr-1" feather="true"></pr-icon>Logs
<a ui-sref="kubernetes.applications.application.logs({ pod: item.PodName, container: item.Name })" class="vertical-center mr-1">
<pr-icon icon="'file-text'" feather="true"></pr-icon>Logs
</a>
<a ng-if="item.Status === 'Running'" ui-sref="kubernetes.applications.application.console({ pod: item.PodName, container: item.Name })" style="margin-left: 10px">
<pr-icon icon="'terminal'" class="mr-1" feather="true"></pr-icon>Console
<a
ng-if="item.Status === 'Running'"
ui-sref="kubernetes.applications.application.console({ pod: item.PodName, container: item.Name })"
class="vertical-center mr-1"
>
<pr-icon icon="'terminal'" feather="true"></pr-icon>Console
</a>
</td>
</tr>

View File

@ -1,4 +1,7 @@
<div class="published-url-container">
<div class="text-muted"> Published URL </div>
<a ng-href="{{ $ctrl.publishedUrl }}" target="_blank" class="publish-url-link"> <i class="fa fa-external-link-alt" aria-hidden="true"></i> {{ $ctrl.publishedUrl }} </a>
<a ng-href="{{ $ctrl.publishedUrl }}" target="_blank" class="publish-url-link vertical-center">
<pr-icon icon="'external-link'" feather="true"></pr-icon>
{{ $ctrl.publishedUrl }}
</a>
</div>

View File

@ -8,7 +8,7 @@
</div>
Applications
</div>
<div class="searchBar vertical-center">
<div class="searchBar vertical-center !mr-0 min-w-[280px]">
<pr-icon icon="'search'" feather="true" class-name="'searchIcon'"></pr-icon>
<input
type="text"
@ -105,10 +105,10 @@
</span>
</div>
</div>
<div class="flex flex-row w-full">
<span class="small text-muted mt-1 vertical-center" ng-if="!$ctrl.settings.showSystem" authorization="K8sAccessSystemNamespaces">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
<span> System resources are hidden, this can be changed in the table settings. </span>
<div class="flex flex-row w-full" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<span class="small text-muted mt-1 vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'" class="vertical-center"></pr-icon>
System resources are hidden, this can be changed in the table settings.
</span>
</div>
</div>

View File

@ -5,11 +5,11 @@
<!-- title -->
<div class="toolBarTitle vertical-center">
<div class="widget-icon space-right">
<pr-icon icon="'repeat'" feather="true"></pr-icon>
<pr-icon icon="'svg-dataflow'" class-name="'[&>*]:mr-0.5'"></pr-icon>
</div>
Port mappings
</div>
<div class="searchBar vertical-center">
<div class="searchBar vertical-center !mr-0 min-w-[300px]">
<pr-icon icon="'search'" feather="true" class-name="'icon !h-3'"></pr-icon>
<input
type="text"
@ -77,8 +77,8 @@
</div>
<!-- info text -->
<div class="flex flex-row w-full">
<span class="small text-muted mt-1" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<pr-icon icon="'info'" feather="true" class-name="'icon'"></pr-icon>
<span class="small text-muted mt-1 vertical-center" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
System resources are hidden, this can be changed in the table settings.
</span>
</div>
@ -162,7 +162,7 @@
</span>
</span>
<!-- Internal -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.CLUSTER_IP"> <i class="fa fa-list-alt mr-0.5" aria-hidden="true"></i> ClusterIP </span>
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.CLUSTER_IP"> <pr-icon icon="'list'" feather="true"></pr-icon> ClusterIP </span>
<!-- Cluster -->
<span ng-if="item.ServiceType === $ctrl.KubernetesServiceTypes.NODE_PORT"> <pr-icon icon="'list'" feather="true" class-name="'icon'"></pr-icon> NodePort </span>
</td>

View File

@ -73,7 +73,7 @@
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon mt-2" aria-hidden="true"></i>
<pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
</span>
</div>
</div>
@ -88,9 +88,9 @@
</div>
</div>
<!-- info text -->
<div class="flex flex-row">
<span class="small text-muted mt-1" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<pr-icon icon="'info'" feather="true"></pr-icon>
<div class="flex flex-row w-full">
<span class="small text-muted mt-1 vertical-center" ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
System resources are hidden, this can be changed in the table settings.
</span>
</div>

View File

@ -75,7 +75,7 @@
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i>
<pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
</span>
</div>
</div>
@ -90,7 +90,7 @@
</div>
<div ng-if="$ctrl.isAdmin && !$ctrl.settings.showSystem" class="flex flex-row w-full">
<span class="small text-muted mt-1 vertical-center">
<pr-icon icon="'info'" feather="true" class-name="'!mb-0.5'" mode="'primary'"></pr-icon>
<pr-icon icon="'info'" feather="true" mode="'primary'" class="vertical-center"></pr-icon>
<div> System resources are hidden, this can be changed in the table settings. </div>
</span>
</div>

View File

@ -2,9 +2,8 @@
<div class="toolBar">
<div class="toolBarTitle flex">
<div class="widget-icon space-right">
<pr-icon icon="'rotate-ccw'" feather="true"></pr-icon>
<pr-icon icon="'svg-clockrewind'" feather="true"></pr-icon>
</div>
{{ $ctrl.titleText }}
</div>
<div class="searchBar">

View File

@ -1,14 +1,14 @@
<div class="datatable">
<rd-widget>
<rd-widget-body classes="no-padding">
<div class="toolBar">
<div class="toolBar !gap-3">
<div class="toolBarTitle vertical-center">
<div class="widget-icon space-right">
<pr-icon icon="$ctrl.titleIcon" feather="true"></pr-icon>
</div>
{{ $ctrl.titleText }}
</div>
<div class="searchBar vertical-center">
<div class="searchBar vertical-center !mr-0 min-w-[280px]">
<pr-icon icon="'search'" feather="true" class="vertical-center"></pr-icon>
<input
type="text"

View File

@ -4,26 +4,25 @@
<div class="toolBar">
<div class="toolBarTitle flex">
<div class="widget-icon space-right">
<pr-icon icon="$ctrl.titleIcon" feather="true"></pr-icon>
<pr-icon icon="'svg-laptopcode'"></pr-icon>
</div>
<span class="vertical-center">
{{ $ctrl.titleText }}
</span>
</div>
<div class="searchBar min-w-[260px]">
<pr-icon icon="'search'" class="vertical-center" class-name="'searchIcon'" feather="true"></pr-icon>
<input
type="text"
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search for an application..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>
</div>
<div class="settings vertical-center">
<div class="searchBar">
<pr-icon icon="'search'" class="vertical-center" feather="true"></pr-icon>
<input
type="text"
class="searchInput ml-1"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search for an application..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>
</div>
<span class="setting" ng-class="{ 'setting-active': $ctrl.settings.open }" uib-dropdown dropdown-append-to-body auto-close="disabled" is-open="$ctrl.settings.open">
<span uib-dropdown-toggle><pr-icon icon="'more-vertical'" feather="true"></pr-icon></span>
<div class="dropdown-menu dropdown-menu-right" uib-dropdown-menu>

View File

@ -3,7 +3,6 @@ angular.module('portainer.kubernetes').component('kubernetesNodeApplicationsData
controller: 'KubernetesNodeApplicationsDatatableController',
bindings: {
titleText: '@',
titleIcon: '@',
dataset: '<',
tableKey: '@',
orderBy: '@',

View File

@ -4,26 +4,25 @@
<div class="toolBar">
<div class="toolBarTitle flex">
<div class="widget-icon space-right">
<pr-icon icon="$ctrl.titleIcon"></pr-icon>
<pr-icon icon="$ctrl.titleIcon" feather="true"></pr-icon>
</div>
<span class="vertical-center">
{{ $ctrl.titleText }}
</span>
</div>
<div class="searchBar vertical-center">
<pr-icon icon="'search'" feather="true"></pr-icon>
<input
type="text"
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search for a node..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>
</div>
<div class="settings">
<div class="searchBar vertical-center">
<pr-icon icon="'search'" feather="true" class-name="'searchIcon'"></pr-icon>
<input
type="text"
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>
</div>
<span
class="setting vertical-center"
ng-class="{ 'setting-active': $ctrl.settings.open }"
@ -132,7 +131,9 @@
ng-click="$ctrl.changeOrderBy('IPAddress')"
></table-column-header>
</th>
<th ng-if="$ctrl.useServerMetrics"> Actions </th>
<th ng-if="$ctrl.useServerMetrics">
<table-column-header col-title="'Actions'" can-sort="false"></table-column-header>
</th>
</tr>
</thead>
<tbody>
@ -154,7 +155,7 @@
<td>{{ item.Version }}</td>
<td>{{ item.IPAddress }}</td>
<td ng-if="$ctrl.useServerMetrics">
<a ui-sref="kubernetes.cluster.node.stats({ name: item.Name })" style="cursor: pointer"> <i class="fa fa-chart-area" aria-hidden="true"></i> Stats </a>
<a ui-sref="kubernetes.cluster.node.stats({ name: item.Name })" class="vertical-center"> <pr-icon icon="'bar-chart'" feather="true"></pr-icon> Stats </a>
</td>
</tr>
<tr ng-if="!$ctrl.dataset">

View File

@ -3,7 +3,7 @@
<rd-widget-body classes="no-padding">
<div class="toolBar">
<div class="toolBarTitle vertical-center">
<pr-icon icon="$ctrl.titleIcon" feather="true"></pr-icon>
<pr-icon icon="$ctrl.titleIcon" feather="true" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
{{ $ctrl.titleText }}
</div>
<div class="searchBar vertical-center">
@ -13,7 +13,7 @@
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search for an application"
placeholder="Search for an application..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>

View File

@ -17,7 +17,7 @@
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search for a namespace"
placeholder="Search for a namespace..."
auto-focus
ng-model-options="{ debounce: 300 }"
data-cy="k8sNamespace-namespaceSearchInput"
@ -68,7 +68,7 @@
<option value="300">5min</option>
</select>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i>
<pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
</span>
</div>
</div>
@ -82,9 +82,9 @@
</div>
</div>
<div class="flex flex-row w-full">
<span class="small text-muted mt-1 vertical-center" ng-if="!$ctrl.settings.showSystem && $ctrl.isAdmin">
<pr-icon icon="'info'" feather="true" class-name="'!mb-0.5'" mode="'primary'"></pr-icon>
<div class="flex flex-row w-full" ng-if="!$ctrl.settings.showSystem && $ctrl.isAdmin">
<span class="small text-muted mt-1 vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'" class="vertical-center"></pr-icon>
<div> System resources are hidden, this can be changed in the table settings. </div>
</span>
</div>

View File

@ -1,6 +1,6 @@
<rd-widget>
<div class="toolBar px-5 pt-5">
<div class="toolBarTitle">
<div class="toolBarTitle vertical-center text-[16px] font-medium">
<div class="widget-icon space-right">
<pr-icon icon="'svg-helm'"></pr-icon>
</div>
@ -31,7 +31,7 @@
<div class="form-group nomargin" ng-show="addUserHelmRepoForm.repo.$invalid">
<div class="small">
<div ng-messages="addUserHelmRepoForm.repo.$error">
<p class="vertical-center" ng-message="pattern"
<p class="vertical-center text-muted" ng-message="pattern"
><pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> A valid URL beginning with http(s) is required.</p
>
</div>
@ -41,7 +41,7 @@
<div class="form-group nomargin" ng-show="$ctrl.doesRepoExist()">
<div class="small">
<div ng-messages="addUserHelmRepoForm.repo.$error">
<p class="vertical-center"><pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Helm repo already exists.</p>
<p class="vertical-center text-muted"><pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Helm repository already exists.</p>
</div>
</div>
</div>

View File

@ -7,7 +7,7 @@
src="$ctrl.model.icon"
fallback-icon="'svg-helm'"
class-name="'blocklist-item-logo h-16 w-auto'"
fallback-class-name="'icon-nested-blue !h-12 !w-12'"
fallback-class-name="'icon-nested-blue !h-12 !w-12 [&>*]:!h-8 [&>*]:!w-auto'"
fallback-mode="'primary'"
size="'xl'"
></fallback-image>

View File

@ -17,7 +17,7 @@
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..."
placeholder="Search for a chart..."
auto-focus
ng-model-options="{ debounce: 300 }"
/>

View File

@ -31,8 +31,7 @@ export default class HelmTemplatesController {
};
}
editorUpdate(content) {
const contentvalues = content.getValue();
editorUpdate(contentvalues) {
if (this.state.originalvalues === contentvalues) {
this.state.isEditorDirty = false;
} else {

View File

@ -5,7 +5,7 @@
<p class="inline-flex flex-row items-center">
<pr-icon icon="'info'" feather="true" class="mr-1 vertical-center" mode="'primary'"></pr-icon>
This is a first version for Helm charts, for more information see this&nbsp;<a
class="text-blue-8 hover:underline hover:text-blue-8"
class="hyperlink"
href="https://www.portainer.io/blog/portainer-now-with-helm-support"
target="_blank"
>blog post</a
@ -132,11 +132,14 @@
yml="true"
placeholder="# Define or paste the content of your values yaml file here"
>
<editor-description>
You can get more information about Helm values file format in the
<a href="https://helm.sh/docs/chart_template_guide/values_files/" target="_blank" class="text-blue-8 hover:text-blue-8 hover:underline"
>official documentation</a
>.
<editor-description class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
<span>
You can get more information about Helm values file format in the
<a href="https://helm.sh/docs/chart_template_guide/values_files/" target="_blank" class="text-blue-8 hover:text-blue-8 hover:underline"
>official documentation</a
>.
</span>
</editor-description>
</web-editor-form>
</div>

View File

@ -1,13 +1,13 @@
<ng-form name="serviceForm">
<div ng-if="$ctrl.isAdmin()" class="small" ng-show="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled">
<p style="margin-top: 10px">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon> No Load balancer is available in this cluster, click
<a ui-sref="kubernetes.cluster.setup">here</a> to configure load balancer.
<p class="text-muted pt-2 vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> No Load balancer is available in this cluster, click
<a class="hyperlink" ui-sref="kubernetes.cluster.setup">here</a> to configure load balancer.
</p>
</div>
<div ng-if="!$ctrl.isAdmin()" class="small" ng-show="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER && !$ctrl.loadbalancerEnabled">
<p style="margin-top: 10px">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon> No Load balancer is available in this cluster, contract your administrator.
<p class="text-muted pt-2 vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> No Load balancer is available in this cluster, contact your administrator.
</p>
</div>
@ -18,16 +18,16 @@
$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.NODE_PORT
"
>
<div ng-show="!$ctrl.multiItemDisable" class="mt-5 mb-5">
<label class="control-label text-left">Published ports</label>
<span class="label label-default interactive ml-10 vertical-center" ng-click="$ctrl.addPort()" data-cy="k8sAppCreate-addNewPortButton">
<div ng-show="!$ctrl.multiItemDisable" class="mt-5 mb-5 vertical-center">
<label class="control-label text-left !pt-0">Published ports</label>
<span class="label label-default interactive ml-2.5 vertical-center" ng-click="$ctrl.addPort()" data-cy="k8sAppCreate-addNewPortButton">
<pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> publish a new port
</span>
</div>
<div ng-repeat="servicePort in $ctrl.servicePorts" class="mt-5 service-form row">
<div class="form-group !mx-0 !pl-0 col-sm-3">
<div class="input-group input-group-sm">
<span class="input-group-addon">container port</span>
<span class="input-group-addon required">Container port</span>
<input
type="number"
class="form-control"
@ -47,17 +47,21 @@
<div class="small mt-1" ng-if="$ctrl.state.duplicates.targetPort.refs[$index] !== undefined">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This container port is already used.
</div>
<div class="small mt-1" ng-messages="serviceForm['container_port_'+$index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number is required.</p>
<p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number must be inside the range 1-65535.</p>
<p ng-message="max"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number must be inside the range 1-65535.</p>
<div class="small mt-1 text-muted" ng-messages="serviceForm['container_port_'+$index].$error">
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number is required.</p>
<p class="vertical-center" ng-message="min"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number must be inside the range 1-65535.</p
>
<p class="vertical-center" ng-message="max"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number must be inside the range 1-65535.</p
>
</div>
</span>
</div>
<div class="form-group !mx-0 !pl-0 col-sm-3">
<div class="input-group input-group-sm">
<span class="input-group-addon">service port</span>
<span class="input-group-addon required">Service port</span>
<input
type="number"
class="form-control"
@ -76,11 +80,15 @@
<div class="small mt-1" ng-if="$ctrl.state.duplicates.servicePort.refs[$index] !== undefined">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This service port is already used.
</div>
<div class="small mt-1">
<div class="small mt-1 text-muted">
<div ng-messages="serviceForm['service_port_'+$index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Service port number is required.</p>
<p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number must be inside the range 1-65535.</p>
<p ng-message="max"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Container port number must be inside the range 1-65535.</p>
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Service port number is required.</p>
<p class="vertical-center" ng-message="min"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Service port number must be inside the range 1-65535.</p
>
<p class="vertical-center" ng-message="max"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Service port number must be inside the range 1-65535.</p
>
</div>
</div>
</span>
@ -88,7 +96,7 @@
<div class="form-group !mx-0 !pl-0 col-sm-3" ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.NODE_PORT">
<div class="input-group input-group-sm">
<span class="input-group-addon">nodeport</span>
<span class="input-group-addon required">Nodeport</span>
<input
type="number"
class="form-control"
@ -97,20 +105,22 @@
placeholder="30080"
ng-min="30000"
ng-max="32767"
required
ng-change="$ctrl.onChangeNodePort()"
data-cy="k8sAppCreate-nodeportPort_{{ $index }}"
/>
</div>
<div class="w-full">
<span>
<div class="small mt-1">
<div class="small mt-1 text-muted">
<div ng-messages="serviceForm['node_port_'+$index].$error">
<p ng-message="min"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Node port number must be inside the range 30000-32767 or blank for system
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Nodeport is required.</p>
<p class="vertical-center" ng-message="min"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Nodeport number must be inside the range 30000-32767 or blank for system
allocated.</p
>
<p ng-message="max"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Node port number must be inside the range 30000-32767 or blank for system
<p class="vertical-center" ng-message="max"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Nodeport number must be inside the range 30000-32767 or blank for system
allocated.</p
>
</div>
@ -120,7 +130,7 @@
</div>
<div class="form-group !mx-0 !pl-0 col-sm-3" ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.LOAD_BALANCER">
<div class="input-group input-group-sm">
<span class="input-group-addon">loadbalancer port</span>
<span class="input-group-addon">Loadbalancer port</span>
<input
type="number"
class="form-control"
@ -138,7 +148,7 @@
<div class="form-group !mx-0 !pl-0 col-sm-3" ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP && $ctrl.ingressType">
<div class="input-group input-group-sm">
<span class="input-group-addon">ingress</span>
<span class="input-group-addon">Ingress</span>
<select
class="form-control"
name="ingress_port_{{ $index }}"
@ -152,9 +162,9 @@
</select>
</div>
<span>
<div class="small mt-5">
<div class="small mt-5 text-muted">
<div ng-messages="serviceForm['ingress_port_'+$index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Ingress selection is required.</p>
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Ingress selection is required.</p>
</div>
</div>
</span>
@ -162,7 +172,7 @@
<div class="form-group !mx-0 !pl-0 col-sm-3" ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP && $ctrl.ingressType">
<div class="input-group input-group-sm">
<span class="input-group-addon">hostname</span>
<span class="input-group-addon">Hostname</span>
<select
class="form-control"
name="hostname_port_{{ $index }}"
@ -176,9 +186,9 @@
</select>
</div>
<span>
<div class="small mt-1">
<div class="small mt-1 text-muted">
<div ng-messages="serviceForm['hostname_port_'+$index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Host is required.</p>
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Hostname is required.</p>
</div>
</div>
</span>
@ -186,7 +196,7 @@
<div class="form-group !mx-0 !pl-0 col-sm-3 clear-both" ng-if="$ctrl.serviceType === $ctrl.KubernetesApplicationPublishingTypes.CLUSTER_IP && $ctrl.ingressType">
<div class="input-group input-group-sm">
<span class="input-group-addon">route</span>
<span class="input-group-addon">Route</span>
<input
class="form-control"
name="ingress_route_{{ $index }}"
@ -199,10 +209,10 @@
/>
</div>
<span>
<div class="small mt-1">
<div class="small mt-1 text-muted">
<div ng-messages="serviceForm['ingress_route_'+$index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Route is required.</p>
<p ng-message="pattern"
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Route is required.</p>
<p class="vertical-center" ng-message="pattern"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This field must consist of alphanumeric characters or the special characters: '-', '_'
or '/'. It must start and end with an alphanumeric character (e.g. 'my-route', or 'route-123').</p
>
@ -236,7 +246,7 @@
<button
ng-disabled="$ctrl.servicePorts.length === 1"
ng-show="!$ctrl.multiItemDisable"
class="btn btn-sm btn-light btn-only-icon"
class="btn btn-sm btn-dangerlight btn-only-icon"
type="button"
ng-click="$ctrl.removePort($index)"
data-cy="k8sAppCreate-rmPortButton_{{ $index }}"

View File

@ -9,13 +9,7 @@
ng-options="item.typeValue as item.typeName for item in $ctrl.state.serviceType"
data-cy="k8sAppCreate-publishingModeDropdown"
></select>
<button
type="button"
class="btn btn-sm btn-default vertical-center"
style="margin-left: 0"
ng-click="$ctrl.addEntry( $ctrl.state.selected )"
data-cy="k8sAppCreate-createServiceButton"
>
<button type="button" class="btn btn-md btn-default vertical-center !ml-0" ng-click="$ctrl.addEntry( $ctrl.state.selected )" data-cy="k8sAppCreate-createServiceButton">
<pr-icon icon="'plus'" size="'sm'" feather="true"></pr-icon> Create service
</button>
</div>
@ -25,8 +19,10 @@
<div class="form-group">
<div class="col-sm-12 form-inline" style="margin-top: 20px" ng-repeat="service in $ctrl.formValues.Services">
<div ng-if="!$ctrl.formValues.Services[$index].Ingress">
<div class="text-muted">
<i class="{{ $ctrl.iconStyle(service.Type) }}" aria-hidden="true" style="margin-right: 2px"></i>
<div class="text-muted vertical-center">
<pr-icon ng-if="$ctrl.serviceType(service.Type) === 'ClusterIP'" icon="'list'" feather="true"></pr-icon>
<pr-icon ng-if="$ctrl.serviceType(service.Type) === 'LoadBalancer'" icon="'svg-dataflow'"></pr-icon>
<pr-icon ng-if="$ctrl.serviceType(service.Type) === 'NodePort'" icon="'list'" feather="true"></pr-icon>
{{ $ctrl.serviceType(service.Type) }}
</div>
<kube-services-item-view
@ -50,17 +46,17 @@
<div ng-if="$ctrl.formValues.Services[$index].Ingress && $ctrl.formValues.OriginalIngresses.length === 0">
<div class="text-muted">
<i class="fa fa-route" aria-hidden="true" style="margin-right: 2px"></i>
<pr-icon icon="'svg-route'" class-name="'mr-0.5'"></pr-icon>
Ingress
</div>
<div ng-if="$ctrl.isAdmin()" class="small">
<p style="margin-top: 10px">
<p class="text-muted pt-2 vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Ingress is not configured in this namespace, select another namespace or click
<a ui-sref="kubernetes.cluster.setup">here</a> to configure ingress.
</p>
</div>
<div ng-if="!$ctrl.isAdmin()" class="small">
<p style="margin-top: 10px">
<p class="text-muted pt-2 vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Ingress is not configured in this namespace, select another namespace or contact your
administrator.
</p>

View File

@ -13,11 +13,11 @@
</p>
</div>
<div class="col-sm-12 small text-muted vertical-center" ng-if="$ctrl.formValues.IsSimple">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true" class="vertical-center"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Switch to advanced mode to copy and paste multiple key/values
</div>
<div class="col-sm-12 small text-muted vertical-center" ng-if="!$ctrl.formValues.IsSimple">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true" class="vertical-center"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Generate a configuration entry per line, use YAML format
</div>
</div>
@ -35,7 +35,7 @@
<div ng-repeat="(index, entry) in $ctrl.formValues.Data" ng-if="$ctrl.formValues.IsSimple">
<div class="form-group">
<label for="configuration_data_key_{{ index }}" class="col-sm-3 col-lg-2 control-label text-left">Key</label>
<label for="configuration_data_key_{{ index }}" class="col-sm-3 col-lg-2 control-label text-left required">Key</label>
<div class="col-sm-8 col-lg-9">
<input
type="text"
@ -76,7 +76,7 @@
</div>
<div class="form-group" ng-if="$ctrl.formValues.IsSimple && !entry.IsBinary">
<label for="configuration_data_value_{{ index }}" class="col-sm-3 col-lg-2 control-label text-left">Value</label>
<label for="configuration_data_value_{{ index }}" class="col-sm-3 col-lg-2 control-label text-left required">Value</label>
<div class="col-sm-8 col-lg-9">
<textarea
class="form-control"
@ -97,7 +97,7 @@
</div>
<div class="form-group" ng-if="$ctrl.formValues.IsSimple && entry.IsBinary">
<label for="configuration_data_value_{{ index }}" class="col-sm-3 col-lg-2 control-label text-left">Value</label>
<label for="configuration_data_value_{{ index }}" class="col-sm-3 col-lg-2 control-label text-left required">Value</label>
<div class="col-sm-8 control-label small text-muted text-left"
>Binary data <portainer-tooltip message="'This key holds binary data and cannot be displayed.'"></portainer-tooltip
></div>
@ -117,15 +117,23 @@
<pr-icon class="vertical-center" icon="'trash-2'" feather="true"></pr-icon> Remove entry
</button>
<span class="small text-muted" ng-if="entry.Used">
<pr-icon icon="'alert-circle'" feather="true" mode="'primary'"></pr-icon>
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
This key is currently used by one or more applications
</span>
</div>
</div>
</div>
<div class="form-group" ng-if="!$ctrl.formValues.IsSimple">
<div class="form-group !px-[15px]" ng-if="!$ctrl.formValues.IsSimple">
<input type="text" ng-model="$ctrl.formValues.DataYaml" required style="display: none" />
<code-editor identifier="kubernetes-configuration-editor" value="$ctrl.formValues.DataYaml" read-only="false" yml="true" on-change="($ctrl.editorUpdate)"></code-editor>
<web-editor-form
identifier="kubernetes-configuration-editor"
value="$ctrl.formValues.DataYaml"
on-change="($ctrl.editorUpdate)"
yml="true"
placeholder="# Define or paste key-value pairs, one pair per line"
>
</web-editor-form>
</div>
</ng-form>

View File

@ -43,15 +43,15 @@ class KubernetesConfigurationDataController {
this.onChangeKey();
}
async editorUpdateAsync(cm) {
if (this.formValues.DataYaml !== cm.getValue()) {
this.formValues.DataYaml = cm.getValue();
async editorUpdateAsync(value) {
if (this.formValues.DataYaml !== value) {
this.formValues.DataYaml = value;
this.isEditorDirty = true;
}
}
editorUpdate(cm) {
return this.$async(this.editorUpdateAsync, cm);
editorUpdate(value) {
return this.$async(this.editorUpdateAsync, value);
}
async onFileLoadAsync(event) {

View File

@ -1,10 +1,9 @@
<div class="row">
<div class="col-sm-12 form-section-title"> Resource reservation </div>
<div class="form-group">
<span class="col-sm-12 text-muted small">
<p>
{{ $ctrl.description }}
</p>
<span class="col-sm-12 text-muted small vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
{{ $ctrl.description }}
</span>
</div>
<div class="form-group" ng-if="$ctrl.memoryLimit !== 0">

View File

@ -1,11 +1,19 @@
<div>
<code-editor identifier="application-details-yaml" read-only="true" value="$ctrl.data"></code-editor>
<div class="p-5">
<web-editor-form
identifier="application-details-yaml"
value="$ctrl.data"
yml="true"
placeholder="# Define or paste the content of your manifest here"
read-only="true"
hide-title="true"
>
</web-editor-form>
<div class="py-5">
<span class="btn btn-light btn-sm" ng-click="$ctrl.copyYAML()">
<pr-icon class="vertical-center" icon="'copy'" feather="true"></pr-icon>
Copy to clipboard
</span>
<span class="btn btn-light btn-sm space-left" ng-click="$ctrl.toggleYAMLInspectorExpansion()">
<span class="btn btn-light btn-sm space-left !ml-0" ng-click="$ctrl.toggleYAMLInspectorExpansion()">
<pr-icon class="vertical-center" icon="'minus'" size="'sm'" ng-if="$ctrl.expanded" feather="true"></pr-icon>
<pr-icon class="vertical-center" icon="'plus'" size="'sm'" ng-if="!$ctrl.expanded" feather="true"></pr-icon>
{{ $ctrl.expanded ? 'Collapse' : 'Expand' }}

View File

@ -38,7 +38,7 @@
<div class="col-sm-12">
<button
type="button"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm !ml-0"
ng-disabled="$ctrl.actionInProgress || $ctrl.form.$invalid || !$ctrl.formValues.Title || !$ctrl.formValues.FileContent"
ng-click="$ctrl.submitAction()"
button-spinner="$ctrl.actionInProgress"

View File

@ -63,9 +63,9 @@ angular
return function (value) {
switch (value) {
case KubernetesApplicationDataAccessPolicies.ISOLATED:
return 'fa-cubes';
return 'svg-cubes';
case KubernetesApplicationDataAccessPolicies.SHARED:
return 'fa-cube';
return 'box';
}
};
})

View File

@ -28,7 +28,7 @@
</div>
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
Note: adding this registry will expose the registry credentials to all users of this namespace
Adding this registry will expose the registry credentials to all users of this namespace.
</div>
</div>

View File

@ -23,7 +23,7 @@
</kubernetes-applications-datatable>
</uib-tab>
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
<uib-tab-heading class="vertical-center"> <pr-icon icon="'repeat'" feather="true"></pr-icon> Port mappings </uib-tab-heading>
<uib-tab-heading class="vertical-center"> <pr-icon icon="'svg-dataflow'"></pr-icon> Port mappings </uib-tab-heading>
<kubernetes-applications-ports-datatable dataset="ctrl.state.ports" table-key="kubernetes.applications.ports" order-by="Name" refresh-callback="ctrl.getApplications">
</kubernetes-applications-ports-datatable>
</uib-tab>

View File

@ -14,15 +14,15 @@
title="'Edit application'"
breadcrumbs="[
{ label:'Namespaces', link:'kubernetes.resourcePools' },
{
{
label:ctrl.application.ResourcePool,
link: 'kubernetes.resourcePools.resourcePool',
link: 'kubernetes.resourcePools.resourcePool',
linkParams:{ id: ctrl.application.ResourcePool }
},
{ label:'Applications', link:'kubernetes.applications' },
{
{
label:ctrl.application.Name,
link: 'kubernetes.applications.application',
link: 'kubernetes.applications.application',
linkParams:{ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool }
},
'Edit',
@ -97,10 +97,12 @@
>
<editor-description>
<span class="text-muted small" ng-show="ctrl.stack.IsComposeFormat">
<p>
<p class="vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that not
all the Compose format options are supported by Kompose at the moment.
<span>
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that
not all the Compose format options are supported by Kompose at the moment.
</span>
</p>
<p>
You can get more information about Compose file format in the
@ -108,8 +110,8 @@
</p>
</span>
<span class="text-muted small" ng-show="!ctrl.stack.IsComposeFormat">
<p>
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<p class="vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
This feature allows you to deploy any kind of Kubernetes resource in this environment (Deployment, Secret, ConfigMap...).
</p>
<p>
@ -124,7 +126,7 @@
<div class="col-sm-12 form-section-title"> Application </div>
<!-- #region NAME FIELD -->
<div class="form-group">
<label for="application_name" class="col-sm-3 col-lg-2 control-label text-left">Name</label>
<label for="application_name" class="col-sm-3 col-lg-2 control-label text-left required">Name</label>
<div class="col-sm-8">
<input
type="text"
@ -142,17 +144,20 @@
</div>
</div>
<div class="form-group" ng-show="kubernetesApplicationCreationForm.application_name.$invalid || ctrl.state.alreadyExists">
<div class="col-sm-12 small">
<div ng-messages="kubernetesApplicationCreationForm.application_name.$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This field is required.</p>
<p ng-message="pattern">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
<div class="small">
<div class="col-sm-3 col-lg-2"></div>
<div class="col-sm-8" ng-messages="kubernetesApplicationCreationForm.application_name.$error">
<p class="text-muted vertical-center" ng-message="required"
><pr-icon class="vertical-center" icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This field is required.</p
>
<p class="text-muted vertical-center" ng-message="pattern">
<pr-icon class="vertical-center" icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
This field must consist of lower case alphanumeric characters or '-', contain at most 63 characters, start with an alphabetic character, and end with an
alphanumeric character (e.g. 'my-name', or 'abc-123').
</p>
</div>
<p ng-if="ctrl.state.alreadyExists">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
<p class="text-muted vertical-center" ng-if="ctrl.state.alreadyExists">
<pr-icon class="vertical-center" icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
An application with the same name already exists inside the selected namespace.
</p>
</div>
@ -166,8 +171,8 @@
model="ctrl.formValues.ImageModel"
ng-if="ctrl.formValues.ResourcePool"
auto-complete="false"
label-class="col-sm-1"
input-class="col-sm-11"
label-class="col-sm-3 col-lg-2"
input-class="col-sm-8"
namespace="ctrl.formValues.ResourcePool.Namespace.Name"
endpoint="ctrl.endpoint"
is-admin="ctrl.isAdmin"
@ -182,8 +187,8 @@
<div class="col-sm-12 form-section-title"> Stack </div>
<!-- #region STACK -->
<div class="form-group">
<div class="col-sm-12 small text-muted">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Portainer can automatically bundle multiple applications inside a stack. Enter a name of a new stack or select an existing stack in the list. Leave empty to
use the application name.
</div>
@ -209,8 +214,8 @@
<div class="col-sm-12 form-section-title"> Environment </div>
<!-- #region ENVIRONMENT VARIABLES -->
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Environment variables</label>
<div class="col-sm-12 vertical-center pt-2.5">
<label class="control-label text-left !pt-0">Environment variables</label>
<span
ng-if="ctrl.formValues.Containers.length <= 1"
class="label label-default interactive vertical-center"
@ -227,7 +232,7 @@
<div style="margin-top: 2px">
<div class="col-sm-4 input-group input-group-sm">
<div class="input-group col-sm-12 input-group-sm" ng-class="{ striked: envVar.NeedsDeletion }">
<span class="input-group-addon">name</span>
<span class="input-group-addon required">name</span>
<input
type="text"
name="environment_variable_name_{{ $index }}"
@ -257,7 +262,12 @@
</div>
<div class="col-sm-2 input-group input-group-sm" ng-if="ctrl.formValues.Containers.length <= 1">
<button ng-if="!envVar.NeedsDeletion" class="btn btn-md btn-light btn-only-icon" type="button" ng-click="ctrl.removeEnvironmentVariable(envVar)">
<button
ng-if="!envVar.NeedsDeletion"
class="btn btn-md btn-dangerlight btn-only-icon !ml-0"
type="button"
ng-click="ctrl.removeEnvironmentVariable(envVar)"
>
<pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon>
</button>
<button
@ -277,7 +287,7 @@
ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined
"
>
<div class="col-sm-4 input-group input-group-sm">
<div class="col-sm-8 input-group input-group-sm">
<div
class="small"
style="margin-top: 5px"
@ -287,19 +297,19 @@
"
>
<ng-messages for="kubernetesApplicationCreationForm['environment_variable_name_' + $index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Environment variable name is required.</p>
<p ng-message="pattern"
<p ng-message="required" class="text-muted vertical-center"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true" class-="vertical-center"></pr-icon> Environment variable name is required.</p
>
<p ng-message="pattern" class="text-muted vertical-center"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This field must consist of alphabetic characters, digits, '_', '-',
or '.', and must not start with a digit (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1'.</p
>
</ng-messages>
<p ng-if="ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined"
<p class="text-muted vertical-center" ng-if="ctrl.state.duplicates.environmentVariables.refs[$index] !== undefined"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This environment variable is already defined.</p
>
</div>
</div>
<div class="col-sm-4 input-group input-group-sm"></div>
<div class="col-sm-2 input-group input-group-sm"></div>
</div>
</div>
</div>
@ -309,8 +319,8 @@
<div class="col-sm-12 form-section-title"> Configurations </div>
<!-- #region CONFIGURATIONS -->
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Configurations</label>
<div class="col-sm-12 vertical-center pt-2.5">
<label class="control-label text-left !pt-0">Configurations</label>
<span
class="label label-default interactive vertical-center"
style="margin-left: 10px"
@ -321,8 +331,8 @@
<pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> add configuration
</span>
</div>
<div class="col-sm-12 small text-muted" style="margin-top: 15px" ng-if="ctrl.formValues.Configurations.length">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<div class="col-sm-12 small text-muted vertical-center" style="margin-top: 15px" ng-if="ctrl.formValues.Configurations.length">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Portainer will automatically expose all the keys of a configuration as environment variables. This behavior can be overridden to filesystem mounts for each
key via the override button.
</div>
@ -341,9 +351,9 @@
data-cy="k8sAppCreate-addConfigSelect_{{ $index }}"
></select>
</div>
<div class="col-sm-3" style="margin-top: 2px">
<div class="col-sm-3">
<button
class="btn btn-sm btn-light vertical-center"
class="btn btn-md btn-light vertical-center !ml-0"
type="button"
ng-if="!config.Overriden"
ng-click="ctrl.overrideConfiguration(index)"
@ -353,7 +363,7 @@
<pr-icon icon="'list'" size="'md'" feather="true"></pr-icon> Override
</button>
<button
class="btn btn-sm btn-light vertical-center"
class="btn btn-md btn-light vertical-center !ml-0"
type="button"
ng-if="config.Overriden"
ng-click="ctrl.resetConfiguration(index)"
@ -363,13 +373,13 @@
<pr-icon icon="'rotate-cw'" size="'md'" feather="true"></pr-icon> Auto
</button>
<button
class="btn btn-sm btn-dangerlight vertical-center"
class="btn btn-md btn-dangerlight vertical-center btn-only-icon h-[34px]"
type="button"
ng-click="ctrl.removeConfiguration(index)"
ng-if="ctrl.formValues.Containers.length <= 1"
data-cy="k8sAppCreate-configRemoveButton"
>
<pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon> Remove
<pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon>
</button>
</div>
<!-- no-override -->
@ -390,16 +400,16 @@
<div ng-repeat="(keyIndex, overridenKey) in config.OverridenKeys" style="margin-top: 2px">
<div class="row">
<div class="col-sm-3 col-lg-2 form-group !m-0"><span>&nbsp;</span></div>
<div class="col-sm-3 form-group" style="margin-left: -11px">
<div class="col-sm-3 form-group !mr-1" style="margin-left: -11px">
<div class="input-group input-group-sm">
<span class="input-group-addon">configuration key</span>
<input type="text" class="form-control" ng-value="overridenKey.Key" disabled />
</div>
</div>
<div class="col-sm-3 form-group" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
<div class="col-sm-3 form-group !mr-1" ng-if="overridenKey.Type === ctrl.ApplicationConfigurationFormValueOverridenKeyTypes.FILESYSTEM">
<div class="input-group input-group-sm">
<span class="input-group-addon">path on disk</span>
<span class="input-group-addon required">path on disk</span>
<input
type="text"
class="form-control"
@ -428,9 +438,11 @@
"
>
<ng-messages for="kubernetesApplicationCreationForm['overriden_key_path_' + index + '_' + keyIndex].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Path is required.</p>
<p class="vertical-center" ng-message="required"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Path is required.</p
>
</ng-messages>
<p ng-if="ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined"
<p class="vertical-center" ng-if="ctrl.state.duplicates.configurationPaths.refs[index + '_' + keyIndex] !== undefined"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This path is already used.</p
>
</div>
@ -459,17 +471,17 @@
<div class="col-sm-12 form-section-title"> Persisting data </div>
<!-- #region PERSISTED FOLDERS -->
<div class="form-group" ng-if="!ctrl.storageClassAvailable()">
<div class="col-sm-12 small text-muted">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
No storage option is available to persist data, contact your administrator to enable a storage option.
</div>
</div>
<div class="form-group" ng-if="ctrl.storageClassAvailable()">
<div class="col-sm-12" style="margin-top: 5px" ng-if="!ctrl.allQuotasExhaustedAndNoVolumesAvailable()">
<label class="control-label text-left">Persisted folders</label>
<div class="col-sm-12 vertical-center pt-2.5" style="margin-top: 5px" ng-if="!ctrl.allQuotasExhaustedAndNoVolumesAvailable()">
<label class="control-label text-left !pt-0">Persisted folders</label>
<span
class="label label-default interactive"
class="label label-default interactive vertical-center"
style="margin-left: 10px"
ng-click="ctrl.addPersistedFolder()"
ng-if="ctrl.isAddPersistentFolderButtonShowed()"
@ -480,7 +492,7 @@
</div>
<div class="col-sm-12" style="margin-top: 5px" ng-if="ctrl.allQuotasExhaustedAndNoVolumesAvailable()">
<span class="small text-muted">
<span class="small text-muted vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
This namespace has exhausted its storage capacity. Contact your administrator to expand the capacity of the namespace.
</span>
@ -489,7 +501,7 @@
<div class="col-sm-12 form-inline" style="margin-top: 10px" ng-repeat="persistedFolder in ctrl.formValues.PersistedFolders">
<div style="margin-top: 2px">
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: persistedFolder.NeedsDeletion }">
<span class="input-group-addon">path in container</span>
<span class="input-group-addon required">path in container</span>
<input
type="text"
class="form-control"
@ -514,7 +526,7 @@
"
>
<label
class="btn btn-primary"
class="btn btn-light"
ng-model="persistedFolder.UseNewVolume"
uib-btn-radio="true"
ng-change="ctrl.useNewVolume($index)"
@ -522,7 +534,7 @@
>New volume</label
>
<label
class="btn btn-primary"
class="btn btn-light"
ng-model="persistedFolder.UseNewVolume"
uib-btn-radio="false"
ng-change="ctrl.useExistingVolume($index)"
@ -533,22 +545,23 @@
</div>
<div class="input-group col-sm-3 input-group-sm" ng-class="{ striked: persistedFolder.NeedsDeletion }" ng-if="persistedFolder.UseNewVolume">
<span class="input-group-addon">requested size</span>
<span class="input-group-addon required">requested size</span>
<input
type="number"
class="form-control"
class="form-control !rounded-none"
name="persisted_folder_size_{{ $index }}"
ng-model="persistedFolder.Size"
placeholder="20"
ng-min="0"
min="0"
required
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
ng-change="ctrl.onChangeVolumeRequestedSize()"
/>
<span class="input-group-addon" style="padding: 0">
<span class="input-group-addon !p-0 !rounded-r-[5px]">
<select
class="form-control w-12 !h-[28px] !border-none !rounded-r-[5px] text-xs"
ng-model="persistedFolder.SizeUnit"
ng-style="{ width: '100%', height: '100%', cursor: ctrl.isEditAndExistingPersistedFolder($index) ? 'not-allowed' : 'auto' }"
ng-style="{ height: '100%', cursor: ctrl.isEditAndExistingPersistedFolder($index) ? 'not-allowed' : 'auto' }"
ng-options="unit for unit in ctrl.state.availableSizeUnits"
ng-disabled="ctrl.isEditAndExistingPersistedFolder($index) || ctrl.formValues.Containers.length > 1"
ng-change="ctrl.onChangeVolumeRequestedSize()"
@ -595,12 +608,12 @@
<div ng-if="!ctrl.isEditAndStatefulSet() && !ctrl.state.useExistingVolume[$index] && ctrl.formValues.Containers.length <= 1">
<button
ng-if="!persistedFolder.NeedsDeletion"
class="btn btn-sm btn-danger"
class="btn btn-sm btn-dangerlight !ml-0 h-[30px]"
type="button"
ng-click="ctrl.removePersistedFolder($index)"
data-cy="k8sAppCreate-rmPersistentFolderButton"
>
<pr-icon icon="'trash-2'" feather="true"></pr-icon>
<pr-icon icon="'trash-2'" feather="true" size="'md'"></pr-icon>
</button>
<button
ng-if="persistedFolder.NeedsDeletion"
@ -616,6 +629,7 @@
</div>
<div
class="flex flex-row gap-x-1"
ng-show="
kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid ||
ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined ||
@ -627,36 +641,36 @@
>
<div class="input-group col-sm-3 input-group-sm">
<div
class="small text-warning"
class="small text-muted"
style="margin-top: 5px"
ng-show="
kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$invalid || ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined
"
>
<ng-messages for="kubernetesApplicationCreationForm['persisted_folder_path_' + $index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Path is required.</p>
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Path is required.</p>
</ng-messages>
<p ng-if="ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
<p class="vertical-center" ng-if="ctrl.state.duplicates.persistedFolders.refs[$index] !== undefined"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This path is already defined.</p
>
</div>
</div>
<div class="input-group col-sm-2 input-group-sm"></div>
<div class="input-group col-sm-5 input-group-sm">
<div class="input-group col-sm-offset-2 col-sm-3 input-group-sm">
<div
class="small text-warning"
class="small text-muted"
style="margin-top: 5px"
ng-show="
kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$invalid || ctrl.state.exceeded.persistedFolders.refs[$index] !== undefined
"
>
<ng-messages for="kubernetesApplicationCreationForm['persisted_folder_size_' + $index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Size is required.</p>
<p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This value must be greater than zero.</p>
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Size is required.</p>
<p class="vertical-center" ng-message="min"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This value must be greater than zero.</p
>
</ng-messages>
<p ng-if="ctrl.state.exceeded.persistedFolders.refs[$index] !== undefined">
<p class="vertical-center" ng-if="ctrl.state.exceeded.persistedFolders.refs[$index] !== undefined">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
You can only request up to
{{ ctrl.state.storages.availabilities[persistedFolder.StorageClass.Name] | kubernetesAppStorageRequestSizeHumanReadable }} for
@ -696,7 +710,7 @@
<!-- access policy options -->
<div class="form-group" style="margin-bottom: 0">
<div class="boxselector_wrapper">
<div class="boxselector_wrapper !px-[15px]">
<div
ng-if="
(!ctrl.state.isEdit && !ctrl.state.persistedFoldersUseExistingVolumes) ||
@ -712,7 +726,7 @@
/>
<label for="data_access_isolated">
<div class="boxselector_header">
<pr-icon icon="'box'" feather="true"></pr-icon>
<pr-icon icon="'svg-cubes'"></pr-icon>
Isolated
</div>
<p>Application will be deployed as a StatefulSet with each instantiating their own data</p>
@ -734,7 +748,7 @@
style="cursor: pointer; border-color: #767676"
>
<div class="boxselector_header">
<pr-icon icon="'box'" feather="true"></pr-icon>
<pr-icon icon="'svg-cubes'"></pr-icon>
Isolated
</div>
<p>Application will be deployed as a StatefulSet with each instantiating their own data</p>
@ -750,7 +764,7 @@
/>
<label for="data_access_shared">
<div class="boxselector_header">
<pr-icon icon="'sliders'" feather="true"></pr-icon>
<pr-icon icon="'box'" feather="true"></pr-icon>
Shared
</div>
<p>Application will be deployed as a Deployment with a shared storage access</p>
@ -782,22 +796,22 @@
<div class="col-sm-12 form-section-title"> Resource reservations </div>
<!-- #region RESOURCE RESERVATIONS -->
<div class="form-group" ng-if="!ctrl.state.resourcePoolHasQuota">
<div class="col-sm-12 small text-muted">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Resource reservations are applied per instance of the application.
</div>
</div>
<div class="form-group" ng-if="ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded()">
<div class="col-sm-12 small text-muted">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
A resource quota is set on this namespace, you must specify resource reservations. Resource reservations are applied per instance of the application. Maximums
are inherited from the namespace quota.
</div>
</div>
<div class="form-group" ng-if="ctrl.state.resourcePoolHasQuota && ctrl.resourceQuotaCapacityExceeded()">
<div class="col-sm-12 small text-danger">
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
This namespace has exhausted its resource capacity and you will not be able to deploy the application. Contact your administrator to expand the capacity of
the namespace.
@ -806,22 +820,22 @@
<!-- memory-limit-input -->
<div
class="form-group"
class="form-group flex"
ng-if="
(!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded())) && ctrl.formValues.Containers.length <= 1
"
>
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px">
Memory
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left flex flex-row items-center">
Memory limit (MB)
<portainer-tooltip
message="'An instance of this application will reserve this amount of memory. If the instance memory usage exceeds the reservation, it might be subject to OOM.'"
>
</portainer-tooltip>
</label>
<div class="col-sm-3">
<div class="col-sm-6">
<slider model="ctrl.formValues.MemoryLimit" floor="ctrl.state.sliders.memory.min" ceil="ctrl.state.sliders.memory.max" step="128"></slider>
</div>
<div class="col-sm-2">
<div class="col-sm-2 vertical-center">
<input
name="memory_limit"
ng-model="ctrl.formValues.MemoryLimit"
@ -834,14 +848,12 @@
data-cy="k8sAppCreate-memoryLimit"
/>
</div>
<div class="col-sm-4">
<p class="small text-muted" style="margin-top: 7px"> Maximum memory usage (<b>MB</b>) </p>
</div>
</div>
<div class="form-group" ng-show="kubernetesApplicationCreationForm.memory_limit.$invalid">
<div class="col-sm-12 small text-warning">
<div class="col-sm-3 col-lg-2"></div>
<div class="col-sm-8 small text-muted">
<div ng-messages="kubernetesApplicationCreationForm.memory_limit.$error">
<p
<p class="vertical-center"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Value must be between {{ ctrl.state.sliders.memory.min }} and
{{ ctrl.state.sliders.memory.max }}
</p>
@ -851,28 +863,26 @@
<!-- !memory-limit-input -->
<!-- cpu-limit-input -->
<div
class="form-group"
class="form-group flex"
ng-if="
(!ctrl.state.resourcePoolHasQuota || (ctrl.state.resourcePoolHasQuota && !ctrl.resourceQuotaCapacityExceeded())) && ctrl.formValues.Containers.length <= 1
"
>
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px">
CPU
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left flex flex-row items-center">
CPU limit
<portainer-tooltip
message="'An instance of this application will reserve this amount of CPU. If the instance CPU usage exceeds the reservation, it might be subject to CPU throttling.'"
>
</portainer-tooltip>
</label>
<div class="col-sm-5">
<div class="col-sm-8">
<slider model="ctrl.formValues.CpuLimit" floor="ctrl.state.sliders.cpu.min" ceil="ctrl.state.sliders.cpu.max" step="0.10" precision="2"></slider>
</div>
<div class="col-sm-4" style="margin-top: 20px">
<p class="small text-muted"> Maximum CPU usage </p>
</div>
</div>
<div class="form-group" ng-if="ctrl.nodeLimitsOverflow()">
<div class="col-sm-12 small text-danger">
<div class="col-sm-3 col-lg-2"></div>
<div class="col-sm-8 small text-muted">
<pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
These reservations would exceed the resources currently available in the cluster.
</div>
@ -888,7 +898,7 @@
<!-- deployment options -->
<div class="form-group" style="margin-bottom: 0">
<div class="boxselector_wrapper">
<div class="boxselector_wrapper !px-[15px]">
<div>
<input
type="radio"
@ -905,7 +915,7 @@
<p>Run one or multiple instances of this container</p>
</label>
</div>
<div style="color: #767676" ng-if="!ctrl.supportGlobalDeployment()">
<div ng-if="!ctrl.supportGlobalDeployment()">
<input type="radio" id="deployment_global" disabled />
<label
for="deployment_global"
@ -913,10 +923,9 @@
tooltip-placement="bottom"
tooltip-class="portainer-tooltip"
uib-tooltip="The storage or access policy used for persisted folders cannot be used with this option"
style="cursor: pointer; border-color: #767676"
>
<div class="boxselector_header">
<i class="fa fa-cubes" aria-hidden="true" style="margin-right: 2px"></i>
<pr-icon icon="'svg-cubes'"></pr-icon>
Global
</div>
<p>Application will be deployed as a DaemonSet with an instance on each node of the cluster</p>
@ -933,10 +942,10 @@
/>
<label for="deployment_global">
<div class="boxselector_header">
<i class="fa fa-cubes" aria-hidden="true" style="margin-right: 2px"></i>
<pr-icon icon="'svg-cubes'"></pr-icon>
Global
</div>
<p>Application will be deployed as a DaemonSet with an instance on each node of the cluster</p>
<p>Application will be deployed as a DaemonSet with an instance on each node of the sdfh</p>
</label>
</div>
</div>
@ -945,8 +954,8 @@
<!-- replica count -->
<div class="form-group form-inline" ng-if="ctrl.formValues.DeploymentType === ctrl.ApplicationDeploymentTypes.REPLICATED">
<div class="col-sm-12">
<label class="control-label text-left"> Instance count </label>
<div class="col-sm-12 vertical-center">
<label class="control-label text-left !pt-0"> Instance count </label>
<input
type="number"
name="replica_count"
@ -964,10 +973,12 @@
</div>
</div>
<div class="form-group" ng-if="kubernetesApplicationCreationForm['replica_count'].$invalid">
<div class="col-sm-12 small">
<div class="col-sm-12 small text-muted">
<ng-messages for="kubernetesApplicationCreationForm['replica_count'].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Instance count is required.</p>
<p ng-message="min"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Instance count must be greater than 0.</p>
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Instance count is required.</p>
<p class="vertical-center" ng-message="min"
><pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> Instance count must be greater than 0.</p
>
</ng-messages>
</div>
</div>
@ -977,33 +988,37 @@
class="form-group"
ng-if="!ctrl.resourceReservationsOverflow() && ctrl.formValues.ReplicaCount > 1 && (ctrl.formValues.CpuLimit !== 0 || ctrl.formValues.MemoryLimit !== 0)"
>
<div class="col-sm-12 small text-muted">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
This application will reserve the following resources:
<b>{{ ctrl.formValues.CpuLimit * ctrl.formValues.ReplicaCount | kubernetesApplicationCPUValue }} CPU</b> and
<b>{{ ctrl.formValues.MemoryLimit * ctrl.formValues.ReplicaCount }} MB</b> of memory.
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
<div>
This application will reserve the following resources:
<b>{{ ctrl.formValues.CpuLimit * ctrl.formValues.ReplicaCount | kubernetesApplicationCPUValue }} CPU</b> and
<b>{{ ctrl.formValues.MemoryLimit * ctrl.formValues.ReplicaCount }} MB</b> of memory.
</div>
</div>
</div>
<div class="form-group" ng-if="ctrl.resourceReservationsOverflow()">
<div class="col-sm-12 small">
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'alert-circle'" mode="'danger'" feather="true"></pr-icon>
This application would exceed available resources. Please review resource reservations or the instance count.
</div>
</div>
<div class="form-group" ng-if="ctrl.state.storages.quotaExceeded">
<div class="col-sm-12 small text-muted">
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
This application would exceed available storage. Please review the persisted folders or the instance count.
</div>
</div>
<div class="form-group" ng-if="!ctrl.supportScalableReplicaDeployment()">
<div class="col-sm-12 small text-muted">
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
The following storage option(s) do not support concurrent access from multiples instances: <code>{{ ctrl.getNonScalableStorage() }}</code
>. You will not be able to scale that application.
<div>
The following storage option(s) do not support concurrent access from multiples instances: <code>{{ ctrl.getNonScalableStorage() }}</code
>. You will not be able to scale that application.
</div>
</div>
</div>
<!-- #endregion -->
@ -1013,8 +1028,10 @@
<div class="form-group" ng-if="ctrl.formValues.DeploymentType !== ctrl.ApplicationDeploymentTypes.GLOBAL && ctrl.state.useServerMetrics">
<div class="col-sm-12">
<label for="enable_auto_scaling" class="control-label text-left"> Enable auto scaling for this application </label>
<label class="switch" style="margin-left: 20px">
<div class="col-sm-3 col-lg-2 pl-0 pt-0">
<label for="enable_auto_scaling" class="control-label text-left"> Enable auto scaling for this application </label>
</div>
<label class="switch ml-4 mt-1">
<input
type="checkbox"
class="form-control"
@ -1022,7 +1039,7 @@
ng-model="ctrl.formValues.AutoScaler.IsUsed"
data-cy="k8sAppCreate-autoScaleCheckbox"
/>
<i></i>
<span class="slider round"></span>
</label>
</div>
</div>
@ -1137,23 +1154,23 @@
<!-- #region PLACEMENTS -->
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">Placement rules</label>
<div class="col-sm-12 vertical-center pt-2.5">
<label class="control-label text-left !pt-0">Placement rules</label>
<span class="label label-default interactive vertical-center" style="margin-left: 10px" ng-click="ctrl.addPlacement()">
<pr-icon icon="'plus'" mode="'alt'" size="'sm'" feather="true"></pr-icon> add rule
</span>
</div>
<div class="col-sm-12 small text-muted" ng-if="ctrl.formValues.Placements.length > 0" style="margin-top: 10px">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
Deploy this application on nodes that respect <b>ALL</b> of the following placement rules. Placement rules are based on node labels.
<div class="col-sm-12 small text-muted vertical-center" ng-if="ctrl.formValues.Placements.length > 0" style="margin-top: 10px">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
<div> Deploy this application on nodes that respect <b>ALL</b> of the following placement rules. Placement rules are based on node labels. </div>
</div>
<div class="col-sm-12 form-inline" style="margin-top: 10px">
<div ng-repeat-start="placement in ctrl.formValues.Placements" style="margin-top: 2px">
<div class="col-sm-5 input-group" ng-class="{ striked: placement.NeedsDeletion }">
<select
class="form-control"
class="form-control !rounded"
ng-model="placement.Label"
ng-options="label as (label.Key | kubernetesNodeLabelHumanReadbleText) for label in ctrl.nodesLabels"
ng-change="ctrl.onChangePlacementLabel($index)"
@ -1164,7 +1181,7 @@
</div>
<div class="col-sm-5 input-group" ng-class="{ striked: placement.NeedsDeletion }">
<select
class="form-control"
class="form-control !rounded"
ng-model="placement.Value"
ng-options="value for value in placement.Label.Values"
ng-disabled="ctrl.isEditAndNotNewPlacement($index)"
@ -1176,7 +1193,7 @@
<div class="col-sm-1 input-group">
<button
ng-if="!placement.NeedsDeletion"
class="btn btn-sm btn-light btn-only-icon"
class="btn btn-md btn-dangerlight btn-only-icon !ml-0"
type="button"
ng-click="ctrl.removePlacement($index)"
data-cy="k8sAppCreate-deletePlacementButton"
@ -1185,7 +1202,7 @@
</button>
<button
ng-if="placement.NeedsDeletion"
class="btn btn-sm btn-light btn-only-icon"
class="btn btn-sm btn-light btn-only-icon !ml-0"
type="button"
ng-click="ctrl.restorePlacement($index)"
data-cy="k8sAppCreate-restorePlacementButton"
@ -1196,8 +1213,8 @@
</div>
<div ng-repeat-end ng-show="ctrl.state.duplicates.placements.refs[$index] !== undefined">
<div class="col-sm-5 input-group">
<div class="small text-warning" style="margin-top: 5px" ng-if="ctrl.state.duplicates.placements.refs[$index] !== undefined">
<p ng-if="ctrl.state.duplicates.placements.refs[$index] !== undefined">
<div class="small text-muted" style="margin-top: 5px" ng-if="ctrl.state.duplicates.placements.refs[$index] !== undefined">
<p class="vertical-center" ng-if="ctrl.state.duplicates.placements.refs[$index] !== undefined">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon> This label is already defined.
</p>
</div>
@ -1218,7 +1235,7 @@
<!-- placement policy options -->
<div class="form-group" style="margin-bottom: 0" ng-if="ctrl.formValues.Placements.length">
<div class="boxselector_wrapper">
<div class="boxselector_wrapper !px-[15px]">
<div>
<input
type="radio"
@ -1316,7 +1333,7 @@
<button
ng-if="ctrl.state.appType === ctrl.KubernetesDeploymentTypes.APPLICATION_FORM"
type="button"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm !ml-0"
ng-disabled="!kubernetesApplicationCreationForm.$valid || ctrl.isDeployUpdateButtonDisabled() || !ctrl.imageValidityIsValid()"
ng-click="ctrl.deployApplication()"
button-spinner="ctrl.state.actionInProgress"

View File

@ -3,9 +3,9 @@
title="'Application details'"
breadcrumbs="[
{ label:'Namespaces', link:'kubernetes.resourcePools' },
{
{
label:ctrl.application.ResourcePool,
link: 'kubernetes.resourcePools.resourcePool',
link: 'kubernetes.resourcePools.resourcePool',
linkParams:{ id: ctrl.application.ResourcePool }
},
{ label:'Applications', link:'kubernetes.applications' },
@ -24,7 +24,7 @@
<rd-widget-body classes="no-padding">
<uib-tabset active="ctrl.state.activeTab" justified="true" type="pills">
<uib-tab index="0" classes="btn-sm" select="ctrl.selectTab(0)">
<uib-tab-heading> <pr-icon icon="'fa-laptop-code'" class-name="'mr-1'"></pr-icon> Application </uib-tab-heading>
<uib-tab-heading> <pr-icon icon="'svg-laptopcode'" class-name="'mr-1'"></pr-icon> Application </uib-tab-heading>
<div style="padding: 20px">
<table class="table">
<tbody>
@ -156,19 +156,19 @@
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
<uib-tab-heading>
<pr-icon icon="'fa-compress-arrows-alt'"></pr-icon> Placement
<pr-icon icon="'svg-compress'"></pr-icon> Placement
<div ng-if="ctrl.state.placementWarning" class="vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
warning
</div>
</uib-tab-heading>
<div class="small text-muted vertical-center" style="padding: 20px">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
The placement component helps you understand whether or not this application can be deployed on a specific node.
</div>
<kubernetes-application-placements-datatable
title-text="Placement constraints/preferences"
title-icon="fa-compress-arrows-alt"
title-icon="svg-compress"
dataset="ctrl.placements"
table-key="kubernetes.application.placements"
order-by="Name"
@ -180,7 +180,7 @@
<uib-tab index="2" classes="btn-sm" select="ctrl.selectTab(2)">
<uib-tab-heading>
<pr-icon icon="'fa-history'"></pr-icon> Events
<pr-icon icon="'svg-clockrewind'"></pr-icon> Events
<div ng-if="ctrl.hasEventWarnings()" class="vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
{{ ctrl.state.eventWarningCount }} warning(s)
@ -188,7 +188,7 @@
</uib-tab-heading>
<kubernetes-events-datatable
title-text="Events"
title-icon="fa-history"
title-icon="svg-clockrewind"
dataset="ctrl.events"
table-key="kubernetes.application.events"
order-by="Date"
@ -200,7 +200,7 @@
<uib-tab index="3" ng-if="ctrl.application.Yaml" select="ctrl.showEditor()" classes="btn-sm">
<uib-tab-heading> <pr-icon icon="'code'" feather="true"></pr-icon> YAML </uib-tab-heading>
<div style="padding-right: 25px" ng-if="ctrl.state.showEditorTab">
<div class="px-5" ng-if="ctrl.state.showEditorTab">
<kubernetes-yaml-inspector key="application-yaml" data="ctrl.application.Yaml"></kubernetes-yaml-inspector>
</div>
</uib-tab>
@ -270,14 +270,14 @@
<div class="text-muted" style="margin-bottom: 15px"> <pr-icon icon="'external-link'" class="mr-1" feather="true"></pr-icon>Accessing the application </div>
<div class="small text-muted" ng-if="ctrl.application.PublishedPorts.length === 0" style="margin-bottom: 15px">
<pr-icon icon="'alert-circle'" mode="'primary'" class="mr-1" feather="true"></pr-icon>This application is not exposing any port.
<pr-icon icon="'info'" mode="'primary'" class="mr-1" feather="true"></pr-icon>This application is not exposing any port.
</div>
<div ng-if="ctrl.application.Services.length !== 0">
<!-- Services notice -->
<div>
<div class="small text-muted">
<p> <pr-icon icon="'alert-circle'" mode="'primary'" class="mr-1" feather="true"></pr-icon>This application is exposed through service(s) as below: </p>
<p> <pr-icon icon="'info'" mode="'primary'" class="mr-1" feather="true"></pr-icon>This application is exposed through service(s) as below: </p>
</div>
</div>
@ -298,7 +298,7 @@
<div class="text-muted" style="margin-bottom: 15px"> <pr-icon icon="'move'" class="mr-1" feather="true"></pr-icon>Auto-scaling </div>
<div class="small text-muted" ng-if="!ctrl.application.AutoScaler" style="margin-bottom: 15px">
<pr-icon icon="'alert-circle'" mode="'primary'" class="mr-1" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" class="mr-1" feather="true"></pr-icon>
This application does not have an autoscaling policy defined.
</div>
@ -333,7 +333,7 @@
</div>
<div class="small text-muted" ng-if="!ctrl.application.Env.length > 0 && !ctrl.hasVolumeConfiguration()" style="margin-bottom: 15px">
<pr-icon icon="'alert-circle'" mode="'primary'" class="mr-1" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" class="mr-1" feather="true"></pr-icon>
This application is not using any environment variable or configuration.
</div>
@ -434,13 +434,14 @@
</div>
<div class="small text-muted" ng-if="!ctrl.hasPersistedFolders()">
<pr-icon icon="'alert-circle'" mode="'primary'" class="mr-1" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" class="mr-1" feather="true"></pr-icon>
This application has no persisted folders.
</div>
<div ng-if="ctrl.hasPersistedFolders()">
<div class="small text-muted" style="margin-bottom: 15px">
Data access policy: <i class="fa {{ ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyIcon }}" aria-hidden="true"></i>
<div class="small text-muted vertical-center" style="margin-bottom: 15px">
Data access policy:
<pr-icon icon="ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyIcon" feather="true"></pr-icon>
{{ ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyText }}
<portainer-tooltip position="'right'" message="ctrl.application.DataAccessPolicy | kubernetesApplicationDataAccessPolicyTooltip"> </portainer-tooltip>
</div>
@ -456,7 +457,10 @@
{{ volume.MountPath }}
</td>
<td ng-if="volume.PersistentVolumeClaimName">
<a ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName, namespace: ctrl.application.ResourcePool })" data-cy="k8sAppDetail-volClaimName"
<a
class="hyperlink"
ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName, namespace: ctrl.application.ResourcePool })"
data-cy="k8sAppDetail-volClaimName"
><pr-icon icon="'database'" class="mr-1" feather="true"></pr-icon>{{ volume.PersistentVolumeClaimName }}</a
>
</td>
@ -491,7 +495,10 @@
{{ volume.MountPath }}
</td>
<td ng-if="volume.PersistentVolumeClaimName">
<a ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName + '-' + container.PodName, namespace: ctrl.application.ResourcePool })">
<a
class="hyperlink"
ui-sref="kubernetes.volumes.volume({ name: volume.PersistentVolumeClaimName + '-' + container.PodName, namespace: ctrl.application.ResourcePool })"
>
<pr-icon icon="'database'" class="mr-1" feather="true"></pr-icon>{{ volume.PersistentVolumeClaimName + '-' + container.PodName }}</a
>
</td>

View File

@ -2,9 +2,8 @@
<div class="toolBar">
<div class="toolBarTitle flex">
<div class="widget-icon space-right">
<pr-icon icon="$ctrl.titleIcon" feather="true"></pr-icon>
<pr-icon icon="$ctrl.titleIcon"></pr-icon>
</div>
<span class="vertical-center">
{{ $ctrl.titleText }}
</span>
@ -56,7 +55,7 @@
</span>
</div>
</div>
<div class="table-responsive">
<div class="table-responsive border-none">
<table class="table table-hover nowrap-cells">
<thead>
<tr>

View File

@ -16,8 +16,8 @@
<td>{{ service.spec.clusterIP }}</td>
<td ng-show="service.spec.type === 'LoadBalancer'">
<div ng-show="service.status.loadBalancer.ingress">
<a target="_blank" ng-href="http://{{ service.status.loadBalancer.ingress[0].ip }}:{{ service.spec.ports[0].port }}">
<i class="fa fa-external-link-alt" aria-hidden="true"></i>
<a class="vertical-center hyperlink" target="_blank" ng-href="http://{{ service.status.loadBalancer.ingress[0].ip }}:{{ service.spec.ports[0].port }}">
<pr-icon icon="'external-link'" feather="true"></pr-icon>
<span data-cy="k8sAppDetail-containerPort"> Access </span>
</a>
</div>
@ -32,8 +32,14 @@
</td>
<td ng-if="!ctrl.portHasIngressRules(port)">
<div ng-repeat="port in service.spec.ports">
<a ng-if="$ctrl.publicUrl && port.nodePort" ng-href="http://{{ $ctrl.publicUrl }}:{{ port.nodePort }}" target="_blank" style="margin-left: 5px">
<i class="fa fa-external-link-alt" aria-hidden="true"></i>
<a
class="vertical-center hyperlink"
ng-if="$ctrl.publicUrl && port.nodePort"
ng-href="http://{{ $ctrl.publicUrl }}:{{ port.nodePort }}"
target="_blank"
style="margin-left: 5px"
>
<pr-icon icon="'external-link'" feather="true"></pr-icon>
<span data-cy="k8sAppDetail-containerPort">
{{ port.port }}
</span>

View File

@ -23,7 +23,7 @@
<div class="toolBarTitle text-muted small vertical-center px-5 !gap-0">
<pr-icon icon="'info'" feather="true" mode="'primary'" class-name="'!mr-1'" class="vertical-center"></pr-icon>
This is a first version for Helm charts, for more information see this&nbsp;
<a href="https://www.portainer.io/blog/portainer-now-with-helm-support" target="_blank" class="text-blue-8 hover:text-blue-8 hover:underline">blog post</a>.
<a href="https://www.portainer.io/blog/portainer-now-with-helm-support" target="_blank" class="hyperlink">blog post</a>.
</div>
<rd-widget-body>
<table class="table">

View File

@ -3,15 +3,15 @@
title="'Application logs'"
breadcrumbs="[
{ label:'Namespaces', link:'kubernetes.resourcePools' },
{
{
label:ctrl.application.ResourcePool,
link: 'kubernetes.resourcePools.resourcePool',
link: 'kubernetes.resourcePools.resourcePool',
linkParams:{ id: ctrl.application.ResourcePool }
},
{ label:'Applications', link:'kubernetes.applications' },
{
{
label:ctrl.application.Name,
link: 'kubernetes.applications.application',
link: 'kubernetes.applications.application',
linkParams:{ name: ctrl.application.Name, namespace: ctrl.application.ResourcePool }
},
'Pods',
@ -26,7 +26,7 @@
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>
<div ng-if="ctrl.state.viewReady" style="height: 100%">
<div ng-if="ctrl.state.viewReady">
<div class="row">
<div class="col-sm-12">
<rd-widget>
@ -75,8 +75,8 @@
</div>
</div>
<div class="row" style="height: 54%">
<div class="col-sm-12" style="height: 100%">
<div class="row">
<div class="col-sm-12 h-[max(400px,calc(100vh-380px))]">
<pre
class="log_viewer widget"
><div ng-repeat="line in ctrl.state.filteredLogs = (ctrl.applicationLogs | filter:ctrl.state.search) track by $index" class="line" ng-if="line"><p class="inner_line">{{ line }}</p></div><div ng-if="ctrl.applicationLogs.length && !ctrl.state.filteredLogs.length" class="line"><p class="inner_line">No log line matching the '{{ ctrl.state.search }}' filter</p></div><div ng-if="ctrl.applicationLogs.length === 0" class="line"><p class="inner_line">No logs available</p></div></pre>

View File

@ -3,15 +3,15 @@
title="'Application stats'"
breadcrumbs="[
{ label:'Namespaces', link:'kubernetes.resourcePools' },
{
{
label:ctrl.state.transition.namespace,
link: 'kubernetes.resourcePools.resourcePool',
link: 'kubernetes.resourcePools.resourcePool',
linkParams:{ id: ctrl.state.transition.namespace }
},
{ label:'Applications', link:'kubernetes.applications' },
{
{
label:ctrl.state.transition.applicationName,
link: 'kubernetes.applications.application',
link: 'kubernetes.applications.application',
linkParams:{ name: ctrl.state.transition.applicationName, namespace: ctrl.state.transition.namespace }
},
'Pods',
@ -28,8 +28,8 @@
<div ng-if="ctrl.state.viewReady">
<information-panel ng-if="!ctrl.state.getMetrics" title-text="Unable to retrieve container metrics">
<span class="small text-muted">
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px"></i>
<span class="small text-muted vertical-center">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Portainer was unable to retrieve any metrics associated to that container. Please contact your administrator to ensure that the Kubernetes metrics feature is properly
configured.
</span>
@ -37,7 +37,12 @@
<div class="row" ng-if="ctrl.state.getMetrics">
<div class="col-md-12">
<rd-widget>
<rd-widget-header icon="fa-info-circle" title-text="About statistics"> </rd-widget-header>
<div class="toolBar pt-5 px-5">
<div class="toolBarTitle flex">
<pr-icon icon="'info'" feather="true" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
<span class="vertical-center"> About statistics </span>
</div>
</div>
<rd-widget-body>
<form class="form-horizontal">
<div class="form-group">
@ -57,12 +62,15 @@
</select>
</div>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i>
<pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
</span>
</div>
<div class="form-group" ng-if="ctrl.state.networkStatsUnavailable">
<div class="col-sm-12">
<span class="small text-muted"> <i class="fa fa-exclamation-triangle orange-icon" aria-hidden="true"></i> Network stats are unavailable for this container. </span>
<span class="small text-muted">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Network stats are unavailable for this container.
</span>
</div>
</div>
</form>
@ -74,7 +82,12 @@
<div class="row" ng-if="ctrl.state.getMetrics">
<div class="col-lg-6 col-md-12 col-sm-12">
<rd-widget>
<rd-widget-header icon="fa-chart-area" title-text="Memory usage"></rd-widget-header>
<div class="toolBar pt-5 px-5">
<div class="toolBarTitle flex">
<pr-icon icon="'svg-memory'" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
<span class="vertical-center"> Memory usage </span>
</div>
</div>
<rd-widget-body>
<div class="chart-container" style="position: relative">
<canvas id="memoryChart" width="770" height="300"></canvas>
@ -84,7 +97,12 @@
</div>
<div class="col-lg-6 col-md-12 col-sm-12" ng-if="!ctrl.state.networkStatsUnavailable">
<rd-widget>
<rd-widget-header icon="fa-chart-area" title-text="CPU usage"></rd-widget-header>
<div class="toolBar pt-5 px-5">
<div class="toolBarTitle flex">
<pr-icon icon="'cpu'" feather="true" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
<span class="vertical-center"> CPU usage </span>
</div>
</div>
<rd-widget-body>
<div class="chart-container" style="position: relative">
<canvas id="cpuChart" width="770" height="300"></canvas>

View File

@ -54,7 +54,7 @@
<div class="col-sm-12">
<kubernetes-nodes-datatable
title-text="Nodes"
title-icon="fa-hdd"
title-icon="hard-drive"
dataset="ctrl.nodes"
table-key="kubernetes.nodes"
order-by="Name"

View File

@ -51,19 +51,21 @@
<tr>
<td class="col-xs-3"> Availability </td>
<td class="col-xs-9">
<select class="form-control" name="availability" style="display: inline-block; width: 16rem" ng-model="ctrl.formValues.Availability">
<option>{{ ctrl.availabilities.ACTIVE }}</option>
<option>{{ ctrl.availabilities.PAUSE }}</option>
<option>{{ ctrl.availabilities.DRAIN }}</option>
</select>
<span class="small vertical-center" ng-if="ctrl.state.isDrainOperation && ctrl.formValues.Availability === ctrl.availabilities.DRAIN">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Cannot use this action while another node is currently being drained.
</span>
<span class="small vertical-center" ng-if="ctrl.state.isContainPortainer && ctrl.formValues.Availability === ctrl.availabilities.DRAIN">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Cannot drain a node where this Portainer instance is running.
</span>
<div class="flex flex-col">
<select class="form-control" name="availability" style="display: inline-block; width: 16rem" ng-model="ctrl.formValues.Availability">
<option>{{ ctrl.availabilities.ACTIVE }}</option>
<option>{{ ctrl.availabilities.PAUSE }}</option>
<option>{{ ctrl.availabilities.DRAIN }}</option>
</select>
<div class="small text-muted vertical-center" ng-if="ctrl.state.isDrainOperation && ctrl.formValues.Availability === ctrl.availabilities.DRAIN">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Cannot use this action while another node is currently being drained.
</div>
<div class="small text-muted vertical-center" ng-if="ctrl.state.isContainPortainer && ctrl.formValues.Availability === ctrl.availabilities.DRAIN">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Cannot drain a node where this Portainer instance is running.
</div>
</div>
</td>
</tr>
</tbody>
@ -126,14 +128,14 @@
>
<pr-icon icon="'x'" feather="true" mode="'error'" size="'sm'"></pr-icon>
</button>
<button ng-if="!ctrl.isSystemLabel($index) && label.NeedsDeletion" class="btn btn-sm btn-primary" type="button" ng-click="ctrl.restoreLabel($index)">
<button ng-if="!ctrl.isSystemLabel($index) && label.NeedsDeletion" class="btn btn-sm btn-secondary" type="button" ng-click="ctrl.restoreLabel($index)">
Restore
</button>
<span class="label label-warning label-sm image-tag" ng-if="label.IsUsed && !ctrl.isSystemLabel($index)" style="margin-left: 5px">used</span>
<span class="label label-info image-tag" ng-if="ctrl.isSystemLabel($index)" style="margin-left: 5px">system</span>
</div>
</div>
<div class="small mt-2" ng-show="kubernetesNodeUpdateForm['label_key_' + $index].$invalid || ctrl.state.duplicateLabelKeys[$index] !== undefined">
<div class="small mt-2 text-muted" ng-show="kubernetesNodeUpdateForm['label_key_' + $index].$invalid || ctrl.state.duplicateLabelKeys[$index] !== undefined">
<ng-messages for="kubernetesNodeUpdateForm['label_key_' + $index].$error">
<p ng-message="required" class="vertical-center"> <pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Label key is required. </p>
</ng-messages>
@ -179,11 +181,11 @@
<button ng-if="!taint.NeedsDeletion" class="btn btn-sm btn-dangerlight btn-only-icon" type="button" ng-click="ctrl.removeTaint($index)">
<pr-icon icon="'x'" feather="true" mode="'error'" size="'sm'"></pr-icon>
</button>
<button ng-if="taint.NeedsDeletion" class="btn btn-sm btn-primary" type="button" ng-click="ctrl.restoreTaint($index)"> Restore </button>
<button ng-if="taint.NeedsDeletion" class="btn btn-sm btn-secondary" type="button" ng-click="ctrl.restoreTaint($index)"> Restore </button>
</div>
</div>
<div
class="small"
class="small text-muted"
style="margin-top: 5px"
ng-show="kubernetesNodeUpdateForm['taint_key_' + $index].$invalid || ctrl.state.duplicateTaintKeys[$index] !== undefined"
>
@ -223,7 +225,7 @@
</uib-tab>
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
<uib-tab-heading>
<div class="flex-center gap-1"> <pr-icon icon="'rotate-ccw'" size="'sm'" feather="true"></pr-icon> Events </div>
<div class="flex-center gap-1"> <pr-icon icon="'svg-clockrewind'" size="'sm'" feather="true"></pr-icon> Events </div>
<div class="flex-center gap-1" ng-if="ctrl.hasEventWarnings()">
<pr-icon icon="'alert-circle'" mode="'warning-alt'" size="'sm'" feather="true"></pr-icon>
{{ ctrl.state.eventWarningCount }} warning(s)
@ -231,7 +233,7 @@
</uib-tab-heading>
<kubernetes-events-datatable
title-text="Events"
title-icon="fa-history"
title-icon="icon-nested-blue"
dataset="ctrl.events"
table-key="kubernetes.node.events"
order-by="Date"
@ -264,7 +266,6 @@
refresh-callback="ctrl.getApplications"
loading="ctrl.state.applicationsLoading"
title-text="Applications running on this node"
title-icon="box"
>
</kubernetes-node-applications-datatable>
</div>

View File

@ -3,9 +3,9 @@
title="'Node stats'"
breadcrumbs="[
{ label:'Cluster', link:'kubernetes.cluster' },
{
{
label:ctrl.state.transition.nodeName,
link: 'kubernetes.cluster.node',
link: 'kubernetes.cluster.node',
linkParams:{name: ctrl.state.transition.nodeName}
},
ctrl.state.transition.nodeName,
@ -17,15 +17,20 @@
<div ng-if="ctrl.state.viewReady">
<information-panel ng-if="!ctrl.state.getMetrics" title-text="Unable to retrieve node metrics">
<span class="small text-muted">
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px"></i>
<span class="small text-muted vertical-center">
<pr-icon icon="'alert-triangle'" feather="true" mode="'primary'"></pr-icon>
Portainer was unable to retrieve any metrics associated to that node. Please contact your administrator to ensure that the Kubernetes metrics feature is properly configured.
</span>
</information-panel>
<div class="row" ng-if="ctrl.state.getMetrics">
<div class="col-md-12">
<rd-widget>
<rd-widget-header icon="fa-info-circle" title-text="About statistics"> </rd-widget-header>
<div class="toolBar pt-5 px-5">
<div class="toolBarTitle flex">
<pr-icon icon="'info'" feather="true" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
<span class="vertical-center"> About statistics </span>
</div>
</div>
<rd-widget-body>
<form class="form-horizontal">
<div class="form-group">
@ -45,7 +50,7 @@
</select>
</div>
<span>
<i id="refreshRateChange" class="fa fa-check green-icon" aria-hidden="true" style="margin-top: 7px; display: none"></i>
<pr-icon id="refreshRateChange" icon="'check'" feather="true" mode="'success'" size="'sm'"></pr-icon>
</span>
</div>
</form>
@ -57,7 +62,12 @@
<div class="row" ng-show="ctrl.state.getMetrics">
<div class="col-lg-6 col-md-12 col-sm-12">
<rd-widget>
<rd-widget-header icon="fa-chart-area" title-text="Memory usage"></rd-widget-header>
<div class="toolBar pt-5 px-5">
<div class="toolBarTitle flex">
<pr-icon icon="'svg-memory'" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
<span class="vertical-center"> Memory usage </span>
</div>
</div>
<rd-widget-body>
<div class="chart-node" style="position: relative">
<canvas id="memoryChart" width="770" height="300"></canvas>
@ -67,7 +77,12 @@
</div>
<div class="col-lg-6 col-md-12 col-sm-12">
<rd-widget>
<rd-widget-header icon="fa-chart-area" title-text="CPU usage"></rd-widget-header>
<div class="toolBar pt-5 px-5">
<div class="toolBarTitle flex">
<pr-icon icon="'cpu'" feather="true" mode="'primary'" class-name="'icon-nested-blue'"></pr-icon>
<span class="vertical-center"> CPU usage </span>
</div>
</div>
<rd-widget-body>
<div class="chart-node" style="position: relative">
<canvas id="cpuChart" width="770" height="300"></canvas>

View File

@ -15,8 +15,8 @@
<form class="form-horizontal" name="kubernetesConfigurationCreationForm" autocomplete="off">
<!-- name -->
<div class="form-group">
<label for="configuration_name" class="col-sm-3 col-lg-2 control-label text-left">Name</label>
<div class="col-sm-8">
<label for="configuration_name" class="col-sm-3 col-lg-2 control-label text-left required">Name</label>
<div class="col-sm-8 col-lg-9">
<input
type="text"
class="form-control"
@ -32,7 +32,8 @@
</div>
</div>
<div class="form-group" ng-show="kubernetesConfigurationCreationForm.configuration_name.$invalid || ctrl.state.alreadyExist">
<div class="col-sm-12 small text-muted">
<div class="col-sm-3 col-lg-2"></div>
<div class="col-sm-8 col-lg-9 small text-muted">
<div ng-messages="kubernetesConfigurationCreationForm.configuration_name.$error">
<p ng-message="required" class="vertical-center"><pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> This field is required.</p>
<p ng-message="pattern" class="vertical-center"
@ -52,7 +53,7 @@
<!-- resource-pool -->
<div class="form-group" ng-if="ctrl.formValues.ResourcePool">
<label for="resource-pool-selector" class="col-sm-3 col-lg-2 control-label text-left">Namespace</label>
<div class="col-sm-8">
<div class="col-sm-8 col-lg-9">
<select
class="form-control"
id="resource-pool-selector"
@ -86,13 +87,13 @@
</div>
<!-- type options -->
<div class="form-group" style="margin-bottom: 0">
<div class="form-group px-[15px]" style="margin-bottom: 0">
<div class="boxselector_wrapper">
<div>
<input type="radio" id="type_basic" ng-value="ctrl.KubernetesConfigurationTypes.CONFIGMAP" ng-model="ctrl.formValues.Type" />
<label for="type_basic" data-cy="k8sConfigCreate-nonSensitiveButton">
<div class="boxselector_header">
<pr-icon icon="'code'" feather="true"></pr-icon>
<pr-icon icon="'svg-filecode'"></pr-icon>
ConfigMap
</div>
<p>This configuration holds non-sensitive information</p>
@ -102,7 +103,7 @@
<input type="radio" id="type_secret" ng-value="ctrl.KubernetesConfigurationTypes.SECRET" ng-model="ctrl.formValues.Type" />
<label for="type_secret" data-cy="k8sConfigCreate-sensitiveButton">
<div class="boxselector_header">
<pr-icon icon="'shield'" feather="true"></pr-icon>
<pr-icon icon="'lock'" feather="true"></pr-icon>
Secret
</div>
<p>This configuration holds sensitive information</p>

View File

@ -60,13 +60,13 @@
<pr-icon icon="'svg-clockrewind'"></pr-icon>
Events
<div ng-if="ctrl.hasEventWarnings()">
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px"></i>
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
{{ ctrl.state.eventWarningCount }} warning(s)
</div>
</uib-tab-heading>
<kubernetes-events-datatable
title-text="Events"
title-icon="fa-history"
title-icon="svg-clockrewind"
dataset="ctrl.events"
table-key="kubernetes.configuration.events"
order-by="Date"
@ -143,9 +143,11 @@
<td>
<div style="white-space: pre-wrap">{{ item.Value }}</div>
<div style="margin-top: 2px">
<span class="btn btn-primary btn-xs" ng-click="ctrl.copyConfigurationValue($index)"> <i class="fa fa-copy space-right" aria-hidden="true"></i>Copy </span>
<span class="btn btn-primary btn-xs" ng-click="ctrl.copyConfigurationValue($index)">
<pr-icon icon="'copy'" feather="true" class-name="'mr-0.5'"></pr-icon>Copy
</span>
<span id="copyValueNotification_{{ $index }}" style="display: none; color: #23ae89; margin-left: 5px" class="small">
<i class="fa fa-check" aria-hidden="true"></i> copied
<pr-icon icon="'check'" feather="true"></pr-icon> copied
</span>
</div>
</td>

View File

@ -3,9 +3,9 @@
title="'Kubernetes features configuration'"
breadcrumbs="[
{ label:'Environments', link:'portainer.endpoints' },
{
{
label:ctrl.endpoint.Name,
link: 'portainer.endpoints.endpoint',
link: 'portainer.endpoints.endpoint',
linkParams:{id: ctrl.endpoint.Id}
},
'Kubernetes configuration'
@ -34,7 +34,7 @@
</div>
<div class="col-sm-12">
<label class="control-label text-left col-sm-3 col-lg-2 px-0"> Allow users to use external load balancer </label>
<label class="control-label text-left col-sm-5 col-lg-4 px-0"> Allow users to use external load balancer </label>
<label class="switch mb-0 col-sm-8">
<input type="checkbox" ng-model="ctrl.formValues.UseLoadBalancer" /><span class="slider round" data-cy="kubeSetup-loadBalancerToggle"></span>
</label>
@ -42,7 +42,7 @@
</div>
<div class="form-group">
<div class="col-sm-12 text-muted small">
<div class="col-sm-12 text-muted small mt-4">
<p> Configuring ingress controllers will allow users to expose application they deploy over a HTTP route. </p>
<p class="mt-1 vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
@ -165,7 +165,7 @@
feature-id="ctrl.limitedFeatureAutoWindow"
tooltip="'Specify a timeframe during which automatic updates can occur in this environment.'"
on-change="(ctrl.onToggleAutoUpdate)"
label-class="'col-sm-3 col-lg-2 px-0 !m-0'"
label-class="'col-sm-5 col-lg-4 px-0 !m-0'"
switch-class="'col-sm-8'"
>
</por-switch-field>
@ -185,7 +185,7 @@
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left col-sm-3 col-lg-2 px-0"> Restrict access to the default namespace </label>
<label class="control-label text-left col-sm-5 col-lg-4 px-0"> Restrict access to the default namespace </label>
<label class="switch col-sm-8">
<input type="checkbox" ng-model="ctrl.formValues.RestrictDefaultNamespace" /><span class="slider round" data-cy="kubeSetup-restrictDefaultNsToggle"></span>
</label>
@ -216,7 +216,7 @@
feature-id="ctrl.limitedFeature"
checked="ctrl.formValues.EnableResourceOverCommit"
on-change="(ctrl.onChangeEnableResourceOverCommit)"
label-class="'col-sm-3 col-lg-2 px-0 !m-0'"
label-class="'col-sm-5 col-lg-4 px-0 !m-0'"
switch-class="'col-sm-8'"
></por-switch-field>
</div>
@ -234,14 +234,14 @@
</div>
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left col-sm-3 col-lg-2 px-0"> Enable features using the metrics API </label>
<label class="control-label text-left col-sm-5 col-lg-4 px-0"> Enable features using the metrics API </label>
<label class="switch col-sm-8">
<input type="checkbox" ng-model="ctrl.formValues.UseServerMetrics" ng-change="ctrl.enableMetricsServer()" />
<span class="slider round" data-cy="kubeSetup-metricsToggle"></span>
</label>
</div>
<div ng-if="ctrl.state.metrics.pending && ctrl.state.metrics.userClick" class="col-sm-12 small text-muted" style="margin-top: 5px">
Checking metrics API... <i class="fa fa-spinner fa-spin" style="margin-left: 2px"></i>
Checking metrics API... <pr-icon icon="'loader'" feather="true" class-name="'ml-0.5'"></pr-icon>
</div>
<div
ng-if="!ctrl.state.metrics.pending && ctrl.state.metrics.isServerRunning && ctrl.state.metrics.userClick"
@ -291,7 +291,7 @@
</tr>
<tr ng-repeat="class in ctrl.StorageClasses">
<td>
<div class="flex-center justify-start">
<div class="flex-row vertical-center">
<label class="switch mr-2 mb-0">
<input type="checkbox" ng-model="class.selected" /><span class="slider round" data-cy="kubeSetup-storageToggle{{ class.Name }}"></span>
</label>
@ -341,7 +341,7 @@
<div class="col-sm-12">
<button
type="submit"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm !ml-0"
ng-click="ctrl.configure()"
ng-disabled="ctrl.state.actionInProgress || !kubernetesClusterSetupForm.$valid || !ctrl.hasValidStorageConfiguration()"
button-spinner="ctrl.state.actionInProgress"

View File

@ -52,7 +52,7 @@
</div>
<div ng-if="ctrl.configurations" data-cy="k8sDashboard-configurations">
<a ui-sref="kubernetes.configurations">
<dashboard-item feather-icon="true" icon="'lock'" type="'Configuration'" value="ctrl.configurations.length"></dashboard-item>
<dashboard-item feather-icon="true" icon="'lock'" type="'ConfigMaps & Secret'" value="ctrl.configurations.length"></dashboard-item>
</a>
</div>
<div ng-if="ctrl.volumes" data-cy="k8sDashboard-volumes">

View File

@ -48,7 +48,7 @@
</div>
<div class="form-group">
<label for="stack_name" class="col-lg-2 col-sm-3 control-label text-left">Name</label>
<label for="stack_name" class="col-lg-2 col-sm-3 control-label text-left required">Name</label>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="ctrl.formValues.StackName" id="stack_name" placeholder="my-app" auto-focus />
</div>
@ -117,10 +117,12 @@
>
<editor-description>
<span class="col-sm-12 text-muted small" ng-show="ctrl.state.DeployType === ctrl.ManifestDeployTypes.COMPOSE">
<p>
<p class="vertical-center">
<pr-icon icon="'alert-circle'" mode="'warning'" feather="true"></pr-icon>
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary that
not all the Compose format options are supported by Kompose at the moment.
<span>
Portainer uses <a href="https://kompose.io/" target="_blank">Kompose</a> to convert your Compose manifest to a Kubernetes compliant manifest. Be wary
that not all the Compose format options are supported by Kompose at the moment.
</span>
</p>
<p>
You can get more information about Compose file format in the
@ -128,8 +130,8 @@
</p>
</span>
<span class="col-sm-12 text-muted small" ng-show="ctrl.state.DeployType === ctrl.ManifestDeployTypes.KUBERNETES">
<p>
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<p class="vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
This feature allows you to deploy any kind of Kubernetes resource in this environment (Deployment, Secret, ConfigMap...).
</p>
<p>
@ -149,7 +151,7 @@
<span class="col-sm-12 text-muted small"> Indicate the URL to the manifest. </span>
</div>
<div class="form-group">
<label for="manifest_url" class="col-sm-3 col-lg-2 control-label text-left">URL</label>
<label for="manifest_url" class="col-sm-3 col-lg-2 control-label text-left required">URL</label>
<div class="col-sm-8">
<input
type="text"
@ -170,7 +172,7 @@
<div class="col-sm-12">
<button
type="button"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm !ml-0"
ng-disabled="!deploymentForm.$valid ||ctrl.disableDeploy()"
ng-click="ctrl.deploy()"
button-spinner="ctrl.state.actionInProgress"

View File

@ -43,6 +43,14 @@
<rd-widget-header icon="svg-userlock" title-text="Create access"></rd-widget-header>
<rd-widget-body>
<form class="form-horizontal">
<div class="form-group">
<span class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
Adding user access will require the affected user(s) to logout and login for the changes to be taken into account.
</p>
</span>
</div>
<div class="form-group">
<label class="col-sm-3 col-lg-2 control-label text-left"> Select user(s) and/or team(s) </label>
<div class="col-sm-9 col-lg-4">
@ -92,7 +100,7 @@
<div class="col-sm-12">
<access-datatable
ng-if="ctrl.authorizedUsersAndTeams"
title-text="Access"
title-text="Namespace access"
title-icon="svg-userlock"
table-key="kubernetes_resourcepool_access"
order-by="Name"

View File

@ -76,19 +76,20 @@
<div ng-if="$ctrl.formValues.HasQuota">
<div class="col-sm-12 form-section-title"> Resource limits </div>
<div>
<div class="form-group" ng-if="$ctrl.formValues.HasQuota && !$ctrl.isQuotaValid()">
<span class="col-sm-12 small text-muted">
<p class="vertical-center"
<div class="form-group">
<span class="col-sm-12 small text-muted" ng-switch on="$ctrl.formValues.HasQuota && !$ctrl.isQuotaValid()">
<p class="vertical-center mb-0" ng-switch-when="true"
><pr-icon class="vertical-center" icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> At least a single limit must be set for the quota to be
valid.
</p>
<p class="vertical-center mb-0" ng-switch-default></p>
</span>
</div>
<!-- memory-limit-input -->
<div class="form-group">
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left"> Memory </label>
<div class="col-sm-3">
<div class="form-group flex flex-row !mb-0">
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left"> Memory limit (MB) </label>
<div class="col-xs-6">
<slider
model="$ctrl.formValues.MemoryLimit"
floor="$ctrl.defaults.MemoryLimit"
@ -99,7 +100,7 @@
>
</slider>
</div>
<div class="col-sm-2">
<div class="col-sm-2 vertical-center">
<input
name="memory_limit"
type="number"
@ -111,29 +112,29 @@
data-cy="k8sNamespaceCreate-memoryLimitInput"
required
/>
<span class="help-block">
<div class="form-group" ng-show="resourcePoolCreationForm.memory_limit.$invalid">
<div class="col-sm-12 small text-muted">
<div ng-messages="resourcePoolCreationForm.pool_name.$error">
<p class="vertical-center"
><pr-icon class="vertical-center" icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Value must be between
{{ $ctrl.defaults.MemoryLimit }} and
{{ $ctrl.state.sliderMaxMemory }}
</p>
</div>
</div>
</div>
<div class="flex flex-row w-full">
<span class="col-sm-3 col-lg-2"></span>
<span class="help-block col-sm-9 col-lg-10">
<div ng-show="resourcePoolCreationForm.memory_limit.$invalid">
<div class="small text-muted">
<div ng-messages="resourcePoolCreationForm.pool_name.$error">
<p class="vertical-center"
><pr-icon class="vertical-center" icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Value must be between
{{ $ctrl.defaults.MemoryLimit }} and
{{ $ctrl.state.sliderMaxMemory }}
</p>
</div>
</div>
</span>
</div>
<div class="col-sm-4">
<p class="small text-muted"> Maximum memory usage (MB) </p>
</div>
</div>
</span>
</div>
<!-- !memory-limit-input -->
<!-- cpu-limit-input -->
<div class="form-group">
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left"> CPU </label>
<div class="col-sm-5">
<div class="form-group flex flex-row">
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left"> CPU limit </label>
<div class="col-xs-8">
<slider
model="$ctrl.formValues.CpuLimit"
floor="$ctrl.defaults.CpuLimit"
@ -145,9 +146,6 @@
>
</slider>
</div>
<div class="col-sm-4">
<p class="small text-muted"> Maximum CPU usage </p>
</div>
</div>
<!-- !cpu-limit-input -->
</div>
@ -159,7 +157,7 @@
<div class="form-group">
<span class="col-sm-12 text-muted small vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
<pr-icon icon="'info'" feather="true" mode="'primary'" class="vertical-center"></pr-icon>
You can set a quota on the amount of external load balancers that can be created inside this namespace. Set this quota to 0 to effectively disable the use of load
balancers in this namespace.
</span>
@ -184,7 +182,7 @@
<div class="form-group">
<span class="col-sm-12 text-muted small vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Quotas can be set on each storage option to prevent users from exceeding a specific threshold when deploying applications. You can set a quota to 0 to effectively
prevent the usage of a specific storage option inside this namespace.
</span>
@ -211,7 +209,7 @@
<div class="form-group" ng-if="$ctrl.formValues.IngressClasses.length > 0">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Enable and configure ingresses available to users when deploying applications.
</p>
</div>
@ -268,8 +266,8 @@
data-cy="namespaceCreate-hostnameInput{{ ic.IngressClass.Name }}_{{ $index }}"
/>
</div>
<div class="col-sm-1 input-group input-group-sm" ng-if="$index > 0">
<button class="btn btn-md btn-dangerlight btn-only-icon !h-[30px]" type="button" ng-click="$ctrl.removeHostname(ic, $index)">
<div class="col-sm-1 input-group input-group-sm !pt-2" ng-if="$index > 0">
<button class="btn btn-md btn-dangerlight btn-only-icon" type="button" ng-click="$ctrl.removeHostname(ic, $index)">
<pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon>
</button>
</div>
@ -282,13 +280,13 @@
"
>
<ng-messages for="resourcePoolCreationForm['hostname_' + ic.IngressClass.Name + '_' + $index].$error">
<p ng-message="required"><pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Hostname is required.</p>
<p ng-message="pattern">
<p class="vertical-center" ng-message="required"><pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Hostname is required.</p>
<p class="vertical-center" ng-message="pattern">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
This field must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com').
</p>
</ng-messages>
<p ng-if="$ctrl.state.duplicates.ingressHosts.refs[ic.IngressClass.Name][$index] !== undefined">
<p class="vertical-center" ng-if="$ctrl.state.duplicates.ingressHosts.refs[ic.IngressClass.Name][$index] !== undefined">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> This hostname is already used.
</p>
</div>
@ -299,7 +297,7 @@
<div ng-repeat-end class="form-group" ng-if="ic.Selected">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="'primary'"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
You can specify a list of annotations that will be associated to the ingress.
</p>
</div>
@ -376,7 +374,7 @@
</div>
<div class="input-group input-group-sm col-sm-1">
<button
class="btn btn-sm btn-dangerlight btn-only-icon !h-[30px]"
class="btn btn-md btn-dangerlight btn-only-icon"
type="button"
ng-click="$ctrl.removeAnnotation(ic, $index)"
data-cy="namespaceCreate-deleteAnnotationButton{{ ic.IngressClass.Name }}"
@ -395,17 +393,17 @@
<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>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Define which registries can be used by users who have access to this namespace.
</p>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 col-lg-2 control-label text-left"> Select registries </label>
<div class="col-sm-9 col-lg-4">
<label class="col-sm-3 col-lg-2 control-label text-left !pt-0"> Select registries </label>
<div class="col-sm-8 col-lg-9">
<span class="small text-muted" ng-if="!$ctrl.registries.length && $ctrl.state.isAdmin">
No registries available. Head over <a ui-sref="portainer.registries">registry view</a> to define container registry.
No registries available. Head over to the <a ui-sref="portainer.registries">registry view</a> to define a container registry.
</span>
<span class="small text-muted" ng-if="!$ctrl.registries.length && !$ctrl.state.isAdmin">
No registries available. Contact your administrator to create a container registry.

View File

@ -104,7 +104,7 @@
{{ path.Host ? path.Host : path.IP }}{{ path.Path }}
</a>
<span ng-if="path.ApplicationName !== '-'">
<i class="fas fa-long-arrow-alt-right" style="margin: 2px"></i>
<pr-icon icon="'svg-arrowright'" class-name="'m-0.5'"></pr-icon>
<a ui-sref="kubernetes.applications.application({ name: path.ApplicationName, namespace: item.Namespace })">{{ path.ApplicationName }}</a>
</span>
<span class="label label-warning image-tag label-margins" ng-if="path.ApplicationName === '-'">unused</span>

View File

@ -77,9 +77,9 @@
<div class="col-sm-12 form-section-title"> Resource limits </div>
<div>
<!-- memory-limit-input -->
<div class="form-group">
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px"> Memory limit </label>
<div class="col-sm-3">
<div class="form-group flex">
<label for="memory-limit" class="col-sm-3 col-lg-2 control-label text-left vertical-center"> Memory limit (MB) </label>
<div class="col-sm-6">
<slider
model="ctrl.formValues.MemoryLimit"
floor="ctrl.ResourceQuotaDefaults.MemoryLimit"
@ -88,7 +88,7 @@
ng-if="ctrl.state.sliderMaxMemory"
></slider>
</div>
<div class="col-sm-2">
<div class="col-sm-2 vertical-center">
<input
name="memory_limit"
type="number"
@ -100,12 +100,10 @@
required
/>
</div>
<div class="col-sm-4">
<p class="small text-muted" style="margin-top: 7px"> Memory limit (<b>MB</b>) </p>
</div>
</div>
<div class="form-group" ng-show="resourcePoolEditForm.memory_limit.$invalid">
<div class="col-sm-12 small text-muted">
<div class="col-sm-3 col-lg-2"></div>
<div class="col-sm-8 small text-muted">
<div ng-messages="resourcePoolEditForm.pool_name.$error">
<p class="vertical-center">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon> Value must be between {{ ctrl.ResourceQuotaDefaults.MemoryLimit }} and
@ -118,7 +116,7 @@
<!-- cpu-limit-input -->
<div class="form-group">
<label for="cpu-limit" class="col-sm-3 col-lg-2 control-label text-left" style="margin-top: 20px"> CPU limit </label>
<div class="col-sm-5">
<div class="col-sm-8">
<slider
model="ctrl.formValues.CpuLimit"
floor="ctrl.ResourceQuotaDefaults.CpuLimit"
@ -128,9 +126,6 @@
ng-if="ctrl.state.sliderMaxCpu"
></slider>
</div>
<div class="col-sm-4" style="margin-top: 20px">
<p class="small text-muted"> Maximum CPU usage </p>
</div>
</div>
<!-- !cpu-limit-input -->
</div>
@ -141,7 +136,7 @@
<div class="form-group">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
You can set a quota on the amount of external load balancers that can be created inside this namespace. Set this quota to 0 to effectively disable the use of
load balancers in this namespace.
</p>
@ -174,7 +169,7 @@
<div class="form-group" ng-if="ctrl.formValues.IngressClasses.length > 0">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Enable and configure ingresses available to users when deploying applications.
</p>
</div>
@ -220,7 +215,7 @@
<div ng-repeat="item in ic.Hosts track by $index" style="margin-top: 2px">
<div class="form-inline">
<div class="col-sm-10 input-group input-group-sm" ng-class="{ striked: item.NeedsDeletion }">
<span class="input-group-addon">Hostname</span>
<span class="input-group-addon required">Hostname</span>
<input
type="text"
class="form-control"
@ -257,7 +252,7 @@
'example.com').
</p>
</ng-messages>
<p ng-if="item.Duplicate">
<p class="vertical-center" ng-if="item.Duplicate">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
This hostname is already used.
</p>
@ -269,7 +264,7 @@
<div ng-repeat-end class="form-group" ng-if="ic.Selected" style="margin-bottom: 20px">
<div class="col-sm-12 small text-muted" style="margin-top: 5px">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
You can specify a list of annotations that will be associated to the ingress.
</p>
</div>
@ -338,8 +333,8 @@
/>
</div>
<div class="col-sm-1 input-group input-group-sm">
<button class="btn btn-sm btn-dangerlight" type="button" ng-click="ctrl.removeAnnotation(ic, $index)">
<pr-icon icon="'trash-2'" feather="true"></pr-icon>
<button class="btn btn-md btn-dangerlight btn-only-icon" type="button" ng-click="ctrl.removeAnnotation(ic, $index)">
<pr-icon icon="'trash-2'" feather="true" size="'md'"></pr-icon>
</button>
</div>
</div>
@ -363,18 +358,18 @@
<div class="form-group">
<div class="col-sm-12 small text-muted">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Define which registries can be used by users who have access to this namespace.
</p>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 col-lg-2 control-label text-left" style="padding-top: 0"> Select registries </label>
<div class="col-sm-9 col-lg-4">
<span class="small text-muted" ng-if="!ctrl.registries.length && ctrl.state.isAdmin">
No registries available. Head over <a ui-sref="portainer.registries">registry view</a> to define container registry.
<label class="col-sm-3 col-lg-2 control-label text-left !pt-0"> Select registries </label>
<div class="col-sm-8 col-lg-9">
<span class="small text-muted" ng-if="!ctrl.registries.length && ctrl.isAdmin">
No registries available. Head over to the <a ui-sref="portainer.registries">registry view</a> to define a container registry.
</span>
<span class="small text-muted" ng-if="!ctrl.registries.length && !ctrl.state.isAdmin">
<span class="small text-muted" ng-if="!ctrl.registries.length && !ctrl.isAdmin">
No registries available. Contact your administrator to create a container registry.
</span>
<span
@ -402,7 +397,7 @@
<div class="form-group">
<span class="col-sm-12 text-muted small">
<p class="vertical-center">
<pr-icon icon="'info'" feather="true" mode="primary"></pr-icon>
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Quotas can be set on each storage option to prevent users from exceeding a specific threshold when deploying applications. You can set a quota to 0 to
effectively prevent the usage of a specific storage option inside this namespace.
</p>
@ -433,7 +428,7 @@
<button
type="button"
ng-if="!ctrl.isSystem"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm !ml-0 !mr-1"
ng-disabled="!resourcePoolEditForm.$valid || ctrl.isUpdateButtonDisabled()"
ng-click="ctrl.updateResourcePool()"
button-spinner="ctrl.state.actionInProgress"
@ -444,7 +439,7 @@
<button
ng-if="!ctrl.isDefaultNamespace"
type="button"
class="btn btn-primary btn-sm"
class="btn btn-light btn-sm !ml-0"
ng-click="ctrl.markUnmarkAsSystem()"
button-spinner="ctrl.state.actionInProgress"
data-cy="k8sNamespaceEdit-markSystem"
@ -459,9 +454,9 @@
</uib-tab>
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
<uib-tab-heading class="vertical-center">
<pr-icon icon="'file-text'" feather="true"></pr-icon> Events
<pr-icon icon="'svg-clockrewind'"></pr-icon> Events
<div ng-if="ctrl.hasEventWarnings()">
<i class="fa fa-exclamation-circle orange-icon" aria-hidden="true" style="margin-right: 2px"></i>
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'" class-name="'mr-0.5'"></pr-icon>
{{ ctrl.state.eventWarningCount }} warning(s)
</div>
</uib-tab-heading>
@ -478,7 +473,7 @@
</uib-tab>
<uib-tab index="2" ng-if="ctrl.pool.Yaml" select="ctrl.showEditor()" classes="btn-sm">
<uib-tab-heading class="vertical-center"><pr-icon icon="'code'" feather="true"></pr-icon> YAML </uib-tab-heading>
<div style="padding-right: 25px" ng-if="ctrl.state.showEditorTab">
<div class="px-5" ng-if="ctrl.state.showEditorTab">
<kubernetes-yaml-inspector key="resource-pool-yaml" data="ctrl.pool.Yaml"></kubernetes-yaml-inspector>
</div>
</uib-tab>

View File

@ -9,7 +9,7 @@
endpoint="ctrl.endpoint"
dataset="ctrl.resourcePools"
table-key="kubernetes.resourcePools"
order-by="Namespace.Name"
order-by="Name"
remove-action="ctrl.removeAction"
refresh-callback="ctrl.getResourcePools"
endpoint="ctrl.endpoint"

View File

@ -2,8 +2,8 @@
ng-if="ctrl.state.viewReady"
title="'Stacks logs'"
breadcrumbs="[
{ label:'Namespaces', link:'kubernetes.resourcePools' },
{ label:ctrl.state.transition.namespace, link:'kubernetes.resourcePools.resourcePool', linkParams:{ id: ctrl.state.transition.namespace } },
{ label:'Namespaces', link:'kubernetes.resourcePools' },
{ label:ctrl.state.transition.namespace, link:'kubernetes.resourcePools.resourcePool', linkParams:{ id: ctrl.state.transition.namespace } },
{ label:'Applications', link:'kubernetes.applications' },
'Stacks',
ctrl.state.transition.name,
@ -14,7 +14,7 @@ ctrl.state.transition.name,
<kubernetes-view-loading view-ready="ctrl.state.viewReady"></kubernetes-view-loading>
<div ng-if="ctrl.state.viewReady" style="height: 100%">
<div ng-if="ctrl.state.viewReady">
<div class="row">
<div class="col-sm-12">
<rd-widget>
@ -23,19 +23,22 @@ ctrl.state.transition.name,
<div class="col-sm-12 form-section-title"> Actions </div>
<!-- auto-refresh -->
<div class="form-group">
<div class="col-sm-12">
<label class="control-label text-left">
Auto-refresh
<portainer-tooltip message="'Automatically refresh logs every 30 seconds'"></portainer-tooltip>
<label class="control-label text-left col-sm-3 col-lg-2 vertical-center !py-2">
Auto-refresh
<portainer-tooltip message="'Automatically refresh logs every 30 seconds'"></portainer-tooltip>
</label>
<div class="col-sm-8 col-sm-9 vertical-center">
<label class="switch col-sm-8 col-sm-9 vertical-center !mb-0">
<input type="checkbox" ng-model="ctrl.state.autoRefresh" ng-change="ctrl.updateAutoRefresh()" />
<span class="slider round"></span>
</label>
<label class="switch" style="margin-left: 20px"> <input type="checkbox" ng-model="ctrl.state.autoRefresh" ng-change="ctrl.updateAutoRefresh()" /><i></i> </label>
</div>
</div>
<!-- !auto-refresh -->
<!-- search -->
<div class="form-group">
<label for="logs_search" class="col-sm-1 control-label text-left"> Search </label>
<div class="col-sm-11">
<label for="logs_search" class="col-sm-3 col-lg-2 control-label text-left"> Search </label>
<div class="col-sm-8 col-lg-9">
<input
class="form-control"
type="text"
@ -51,7 +54,10 @@ ctrl.state.transition.name,
<!-- actions -->
<div class="form-group">
<div class="col-sm-12">
<button class="btn btn-primary btn-sm" type="button" ng-click="ctrl.downloadLogs()" style="margin-left: 0"><i class="fa fa-download"></i> Download logs</button>
<button class="btn btn-primary btn-sm !ml-0 vertical-center" type="button" ng-click="ctrl.downloadLogs()">
<pr-icon icon="'download'" feather="true"></pr-icon>
Download logs
</button>
</div>
</div>
<!-- !actions -->
@ -61,8 +67,8 @@ ctrl.state.transition.name,
</div>
</div>
<div class="row" style="height: 54%">
<div class="col-sm-12" style="height: 100%">
<div class="row">
<div class="col-sm-12 h-[max(400px,calc(100vh-380px))]">
<pre
class="log_viewer"
><div ng-repeat="line in ctrl.state.filteredLogs = (ctrl.stackLogs | filter:ctrl.state.search) track by $index" class="line" ng-if="line"><p class="inner_line"><span ng-style="{'color': line.Color, 'font-weight': 'bold'};">{{ line.AppName }}</span> {{ line.Line }}</p></div><div ng-if="ctrl.stackLogs.length && !ctrl.state.filteredLogs.length" class="line"><p class="inner_line">No log line matching the '{{ ctrl.state.search }}' filter</p></div><div ng-if="ctrl.stackLogs.length === 0" class="line"><p class="inner_line">No logs available</p></div></pre>

View File

@ -1,11 +1,11 @@
<div class="flex justify-start form-section-title interactive" ng-click="$ctrl.toggleSummary()" ng-if="$ctrl.state.resources.length > 0">
<pr-icon icon="$ctrl.state.expandedTemplate ? 'chevron-down' : 'chevron-right'" feather="true" class="!mr-1 vertical-center pb-1"></pr-icon>
<div class="flex justify-start items-center form-section-title interactive" ng-click="$ctrl.toggleSummary()" ng-if="$ctrl.state.resources.length > 0">
<pr-icon icon="$ctrl.state.expandedTemplate ? 'chevron-down' : 'chevron-right'" feather="true" class="!mr-1 vertical-center"></pr-icon>
Summary
</div>
<div class="form-group" ng-if="$ctrl.state.expandedTemplate">
<div class="col-sm-12 small text-muted">
<pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon>
<div class="col-sm-12 small text-muted vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
Portainer will execute the following Kubernetes actions.
</div>

View File

@ -4,7 +4,7 @@
<div class="toolBar vertical-center !gap-x-5 !gap-y-1 flex-wrap !p-0 w-full">
<div class="toolBarTitle vertical-center">
<div class="widget-icon space-right">
<pr-icon icon="'database'" feather="true"></pr-icon>
<pr-icon icon="'hard-drive'" feather="true"></pr-icon>
</div>
Storage
</div>

View File

@ -142,7 +142,7 @@
<uib-tab index="1" classes="btn-sm" select="ctrl.selectTab(1)">
<uib-tab-heading class="vertical-center" data-cy="k8sVolDetail-volEventsTab">
<pr-icon icon="'file-text'" feather="true"></pr-icon> Events
<pr-icon icon="'svg-clockrewind'" feather="true"></pr-icon> Events
<div ng-if="ctrl.hasEventWarnings()">
<pr-icon icon="'alert-triangle'" feather="true" mode="'warning'"></pr-icon>
{{ ctrl.state.eventWarningCount }} warning(s)

View File

@ -16,7 +16,7 @@
<!-- !access-control-switch -->
<!-- restricted-access -->
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled" style="margin-bottom: 0">
<div class="boxselector_wrapper">
<div class="boxselector_wrapper px-[15px]">
<div ng-if="$ctrl.isAdmin">
<input type="radio" id="access_administrators" ng-model="$ctrl.formData.Ownership" value="administrators" />
<label for="access_administrators" data-cy="portainer-selectAdminAccess">

View File

@ -1,7 +1,7 @@
<ng-form name="commonCustomTemplateForm">
<!-- title-input -->
<div class="form-group mb-0">
<label for="template_title" class="col-sm-3 col-lg-2 control-label text-left"> Title </label>
<label for="template_title" class="col-sm-3 col-lg-2 control-label text-left required"> Title </label>
<div class="col-sm-8">
<input
type="text"
@ -33,7 +33,7 @@
<!-- description-input -->
<div class="form-group mb-0">
<label for="description" class="col-sm-3 col-lg-2 control-label text-left">Description</label>
<label for="description" class="col-sm-3 col-lg-2 control-label text-left required">Description</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="description" ng-model="$ctrl.formValues.Description" name="description" required />
<span class="help-block">

View File

@ -12,8 +12,7 @@
<option value="" label="Select a Custom template" disabled selected="selected"> </option>
</select>
<span class="small text-muted pt-[7px]" ng-if="!$ctrl.templates.length">
No custom templates are available. Head over to the <a class="text-blue-8 hover:underline hover:text-blue-8" ui-state="$ctrl.newTemplatePath">custom template view</a> to
create one.
No custom templates are available. Head over to the <a class="hyperlink" ui-state="$ctrl.newTemplatePath">custom template view</a> to create one.
</span>
</div>
</div>

View File

@ -2,7 +2,10 @@
<rd-widget>
<rd-widget-body classes="no-padding">
<div class="toolBar vertical-center !gap-x-5 !gap-y-1 flex-wrap">
<rd-widget-header icon="{{ $ctrl.titleIcon }}" feather-icon="true" title-text="Custom Templates" class="!flex-auto !mr-0" parent-classes="!p-0"></rd-widget-header>
<div class="toolBarTitle vertical-center">
<pr-icon icon="$ctrl.titleIcon" feather="true" class-name="'icon-nested-blue'" mode="'primary'"></pr-icon>
Custom Templates
</div>
<div class="searchBar vertical-center !mr-0">
<pr-icon icon="'search'" feather="true" class-name="'searchIcon'"></pr-icon>
<input

View File

@ -3,7 +3,8 @@
overflow: auto;
padding: 20px;
font-size: 16px;
border-radius: 8px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
display: flex;
align-items: center;

View File

@ -99,9 +99,11 @@
{{ item.URL }}
</td>
<td>
<a ng-if="$ctrl.canManageAccess(item)" ng-click="$ctrl.redirectToManageAccess(item)"> <pr-icon icon="'users'" feather="true"></pr-icon> Manage access </a>
<a class="vertical-center" ng-if="$ctrl.canManageAccess(item)" ng-click="$ctrl.redirectToManageAccess(item)">
<pr-icon icon="'users'" feather="true"></pr-icon> Manage access
</a>
<be-feature-indicator feature="$ctrl.limitedFeature" ng-if="$ctrl.canBrowse(item)">
<span class="text-muted space-left" style="padding-right: 5px"> <pr-icon icon="'search'" feather="true" class-name="'searchIcon'"></pr-icon> Browse </span>
<span class="text-muted space-left" style="padding-right: 5px"> <pr-icon icon="'search'" feather="true"></pr-icon> Browse </span>
</be-feature-indicator>
<span ng-if="!$ctrl.canBrowse(item) && !$ctrl.canManageAccess(item)"> - </span>

View File

@ -11,6 +11,7 @@ export const webEditorForm = {
value: '<',
readOnly: '<',
onChange: '<',
hideTitle: '<',
},
transclude: {

View File

@ -1,9 +1,7 @@
<ng-form name="$ctrl.webEditorForm">
<div class="web-editor">
<div class="col-sm-12 form-section-title"> Web editor </div>
<div class="form-group col-sm-12 col-lg-12">
<div class="text-muted small" ng-transclude="description"> </div>
</div>
<div class="web-editor overflow-auto">
<div ng-if="!$ctrl.hideTitle" class="col-sm-12 form-section-title">Web editor</div>
<div class="trancluded-item form-group col-sm-12 col-lg-12 text-muted small" ng-transclude="description"></div>
<div class="form-group">
<div class="col-sm-12 col-lg-12">
<code-editor

View File

@ -2,7 +2,7 @@
<div class="form-group col-sm-12">
<div class="form-inline mt-3">
<div class="input-group col-sm-5 input-group-sm">
<span class="input-group-addon">path</span>
<span class="input-group-addon required">path</span>
<input
type="text"
name="name"
@ -13,7 +13,7 @@
required
/>
</div>
<button class="btn btn-sm btn-light btn-only-icon" type="button" ng-click="$ctrl.removeValue()" title="Remove">
<button class="btn btn-sm btn-dangerlight btn-only-icon" type="button" ng-click="$ctrl.removeValue()" title="Remove">
<pr-icon icon="'trash-2'" size="'md'" feather="true"></pr-icon>
</button>
</div>

View File

@ -17,7 +17,7 @@
</div>
<div ng-if="$ctrl.model.RepositoryAuthentication" class="row">
<div class="form-group">
<label for="repository_username" class="col-lg-2 col-sm-3 control-label text-left"> Username </label>
<label for="repository_username" class="col-lg-2 col-sm-3 control-label text-left required"> Username </label>
<div class="col-sm-8">
<input
type="text"
@ -30,9 +30,9 @@
/>
</div>
</div>
<div class="form-group">
<label for="repository_password" class="col-lg-2 col-sm-3 control-label text-left">
Personal Access Token
<div class="form-group flex">
<label for="repository_password" class="col-lg-2 col-sm-3 control-label text-left !pt-0">
<div class="required"> Personal Access Token </div>
<portainer-tooltip message="'Provide a personal access token or password'"></portainer-tooltip>
</label>
<div class="col-sm-8">

View File

@ -11,7 +11,7 @@
></por-switch-field>
</div>
</div>
<div class="small" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
<div class="small vertical-center" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
<pr-icon icon="'alert-triangle'" mode="'warning'" feather="true"></pr-icon>
<span class="text-muted">Any changes to this stack or application made locally in Portainer will be overridden, which may cause service interruption.</span>
</div>
@ -35,8 +35,8 @@
<label for="repository_mechanism" class="col-sm-3 col-lg-2 control-label text-left"> Webhook </label>
<div class="col-sm-8">
<span class="text-muted"> {{ $ctrl.model.RepositoryWebhookURL | truncatelr }} </span>
<button type="button" class="btn btn-sm btn-light btn-sm space-left" ng-if="$ctrl.model.RepositoryWebhookURL" ng-click="$ctrl.copyWebhook()">
<span><pr-icon icon="'copy'" size="'sm'" feather="true"></pr-icon> Copy link</span>
<button type="button" class="btn btn-sm btn-light btn-sm space-left vertical-center" ng-if="$ctrl.model.RepositoryWebhookURL" ng-click="$ctrl.copyWebhook()">
<pr-icon icon="'copy'" size="'sm'" feather="true"></pr-icon> Copy link
</button>
<span>
<pr-icon icon="'check'" mode="'success'" feather="true" style="display: none"></pr-icon>
@ -44,7 +44,7 @@
</div>
</div>
<div class="form-group" ng-if="$ctrl.model.RepositoryAutomaticUpdates && $ctrl.model.RepositoryMechanism === 'Interval'">
<label for="repository_fetch_interval" class="col-sm-3 col-lg-2 control-label text-left"> Fetch interval </label>
<label for="repository_fetch_interval" class="col-sm-3 col-lg-2 control-label text-left required"> Fetch interval </label>
<div class="col-sm-8">
<input
type="text"
@ -94,11 +94,11 @@
></por-switch-field>
</div>
</div>
<div class="small" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
<div class="small vertical-center" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
<span class="text-muted">When enabled, enforces automatic deployment at each interval or webhook invocation.</span>
</div>
<div class="small" ng-if="!$ctrl.model.RepositoryAutomaticUpdates">
<div class="small vertical-center" ng-if="!$ctrl.model.RepositoryAutomaticUpdates">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
<span class="text-muted">When enabled, updates from the git repository will occur automatically at an interval or webhook.</span>
</div>

View File

@ -1,12 +1,12 @@
<ng-form name="pathForm">
<div class="form-group">
<span class="col-sm-12 text-muted small"
><pr-icon icon="'alert-circle'" mode="'primary'" feather="true"></pr-icon> Indicate the path to the {{ $ctrl.deployMethod == 'compose' ? 'Compose' : 'Manifest' }} file from
the root of your repository (requires a yaml, yml, json, or hcl file extension)
<span class="col-sm-12 text-muted small vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon> Indicate the path to the {{ $ctrl.deployMethod == 'compose' ? 'Compose' : 'Manifest' }} file from the root
of your repository (requires a yaml, yml, json, or hcl file extension)
</span>
</div>
<div class="form-group">
<label for="stack_repository_path" class="col-lg-2 col-sm-3 control-label text-left">{{ $ctrl.deployMethod == 'compose' ? 'Compose' : 'Manifest' }} path</label>
<label for="stack_repository_path" class="col-lg-2 col-sm-3 control-label text-left required">{{ $ctrl.deployMethod == 'compose' ? 'Compose' : 'Manifest' }} path</label>
<div class="col-sm-8">
<input
type="text"

View File

@ -1,7 +1,10 @@
<div class="form-group">
<span class="col-sm-12 text-muted small">
Specify a reference of the repository using the following syntax: branches with <code>refs/heads/branch_name</code> or tags with <code>refs/tags/tag_name</code>. If not
specified, will use the default <code>HEAD</code> reference normally the <code>master</code> branch.
<span class="col-sm-12 text-muted small vertical-center">
<pr-icon icon="'info'" mode="'primary'" feather="true"></pr-icon>
<span>
Specify a reference of the repository using the following syntax: branches with <code>refs/heads/branch_name</code> or tags with <code>refs/tags/tag_name</code>. If not
specified, will use the default <code>HEAD</code> reference normally the <code>master</code> branch.
</span>
</span>
</div>
<div class="form-group">

View File

@ -2,7 +2,7 @@
<span class="col-sm-12 text-muted small"> You can use the URL of a git repository. </span>
</div>
<div class="form-group">
<label for="stack_repository_url" class="col-lg-2 col-sm-3 control-label text-left">Repository URL</label>
<label for="stack_repository_url" class="col-lg-2 col-sm-3 control-label text-left required">Repository URL</label>
<div class="col-sm-8">
<input
type="text"

View File

@ -1,7 +1,7 @@
<div class="row" ng-if="$ctrl.registry">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="svg-plug" title-text="Registry"></rd-widget-header>
<rd-widget-header icon="radio" feather-icon="true" title-text="Registry"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>

View File

@ -2,11 +2,14 @@
<div ng-class="{ 'blocklist-item--selected': $ctrl.model.Selected }" class="blocklist-item template-item !mr-0 !my-0" ng-click="$ctrl.onSelect($ctrl.model)">
<div class="blocklist-item-box">
<!-- template-image -->
<div ng-if="$ctrl.model.Logo" class="vertical-center justify-center">
<img class="blocklist-item-logo" ng-src="{{ $ctrl.model.Logo }}" />
</div>
<div class="blocklist-item-logo vertical-center justify-center" ng-if="!$ctrl.model.Logo">
<pr-icon icon="'svg-rocket'" class-name="'[&>*]:!h-10 [&>*]:!w-auto [&>*>path]:stroke-blue-8'" mode="'primary'"></pr-icon>
<div class="vertical-center justify-center min-w-[56px]">
<fallback-image
src="$ctrl.model.Logo"
fallback-icon="'svg-rocket'"
class-name="'blocklist-item-logo'"
fallback-class-name="'!h-14 !w-14 [&>*]:!h-8 [&>*]:!w-auto icon-nested-blue'"
fallback-mode="'primary'"
></fallback-image>
</div>
<!-- !template-image -->
<!-- template-details -->

View File

@ -49,7 +49,7 @@
<div class="col-sm-12">
<button
type="button"
class="btn btn-primary btn-sm"
class="btn btn-primary btn-sm !ml-0"
ng-disabled="$ctrl.actionInProgress || customTemplateForm.$invalid
|| !$ctrl.formValues.Title
|| !$ctrl.formValues.FileContent

View File

@ -17,6 +17,7 @@ import checked from '@/assets/ico/checked.svg?c';
import circlenotch from '@/assets/ico/circle-notch.svg?c';
import clockrewind from '@/assets/ico/clock-rewind.svg?c';
import compress from '@/assets/ico/compress.svg?c';
import cubes from '@/assets/ico/cubes.svg?c';
import custom from '@/assets/ico/custom.svg?c';
import dataflow from '@/assets/ico/dataflow-1.svg?c';
import dataflow2 from '@/assets/ico/dataflow-2.svg?c';
@ -96,6 +97,7 @@ export const SvgIcons = {
circlenotch,
clockrewind,
compress,
cubes,
custom,
expand,
filecode,

View File

@ -6,3 +6,13 @@
.inner-datatable table thead {
border-top: none !important;
}
.inner-datatable tr > th:first-child,
.inner-datatable tr > td:first-child {
padding-left: 20px;
}
.inner-datatable tr > th:last-child,
.inner-datatable tr > td:last-child {
padding-right: 20px;
}

View File

@ -6,14 +6,20 @@
width: 100vw;
z-index: 1000;
height: 495px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.root.minimized {
height: 35px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.header {
height: 35px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
@ -21,11 +27,11 @@
background: rgb(245, 245, 245);
border-top: 1px solid rgb(190, 190, 190);
padding: 0 30px;
padding: 0 16px;
}
.title {
font-weight: bold;
font-weight: 500;
font-size: 14px;
}
@ -36,5 +42,6 @@
.terminal-container .loading-message {
position: fixed;
padding: 10px 16px 0px 16px;
color: #fff;
}

View File

@ -12,6 +12,7 @@ import { EnvironmentId } from '@/portainer/environments/types';
import { error as notifyError } from '@/portainer/services/notifications';
import { useLocalStorage } from '@/portainer/hooks/useLocalStorage';
import { Icon } from '@@/Icon';
import { Button } from '@@/buttons';
import styles from './KubectlShell.module.css';
@ -125,27 +126,26 @@ export function KubeCtlShell({ environmentId, onClose }: Props) {
return (
<div className={clsx(styles.root, { [styles.minimized]: shell.minimized })}>
<div className={styles.header}>
<div className={styles.title}>
<i className="fas fa-terminal space-right" />
<div className={clsx(styles.title, 'vertical-center')}>
<Icon icon="terminal" feather />
kubectl shell
</div>
<div className={clsx(styles.actions, 'space-x-8')}>
<Button color="link" onClick={clearScreen}>
<i className="fas fa-redo-alt" data-cy="k8sShell-refreshButton" />
<Icon icon="rotate-cw" feather size="md" />
</Button>
<Button color="link" onClick={toggleMinimize}>
<i
className={clsx(
'fas',
shell.minimized ? 'fa-window-restore' : 'fa-window-minimize'
)}
<Icon
icon={shell.minimized ? 'maximize-2' : 'minimize-2'}
feather
size="md"
data-cy={
shell.minimized ? 'k8sShell-restore' : 'k8sShell-minimise'
}
/>
</Button>
<Button color="link" onClick={handleClose}>
<i className="fas fa-times" data-cy="k8sShell-closeButton" />
<Icon icon="x" feather size="md" />
</Button>
</div>
</div>

View File

@ -1,5 +1,5 @@
.root {
display: block;
margin: 0 auto;
margin: -5px auto -8px auto;
padding-bottom: 5px;
}

View File

@ -1,3 +1,4 @@
import clsx from 'clsx';
import { useState } from 'react';
import { createPortal } from 'react-dom';
@ -5,6 +6,7 @@ import { EnvironmentId } from '@/portainer/environments/types';
import { useAnalytics } from '@/angulartics.matomo/analytics-services';
import { Button } from '@@/buttons';
import { Icon } from '@@/Icon';
import { KubeCtlShell } from './KubectlShell';
import styles from './KubectlShellButton.module.css';
@ -19,13 +21,14 @@ export function KubectlShellButton({ environmentId }: Props) {
<>
<Button
color="primary"
size="xsmall"
size="small"
disabled={open}
data-cy="k8sSidebar-shellButton"
onClick={() => handleOpen()}
className={styles.root}
className={clsx(styles.root, '!flex')}
>
<i className="fa fa-terminal space-right" /> kubectl shell
<Icon icon="terminal" feather className="vertical-center" size="md" />{' '}
kubectl shell
</Button>
{open &&