mirror of https://github.com/rancher/ui.git
commit
b6069d80bd
|
|
@ -0,0 +1,206 @@
|
|||
import Controller from '@ember/controller';
|
||||
import { get, computed } from '@ember/object';
|
||||
import {
|
||||
searchFields as containerSearchFields
|
||||
} from 'shared/components/pod-dots/component';
|
||||
|
||||
const podsHeaders = [
|
||||
{
|
||||
name: 'expand',
|
||||
sort: false,
|
||||
searchField: null,
|
||||
width: 30
|
||||
},
|
||||
{
|
||||
name: 'state',
|
||||
sort: ['sortState', 'displayName'],
|
||||
searchField: 'displayState',
|
||||
translationKey: 'generic.state',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
sort: ['sortName', 'id'],
|
||||
searchField: 'displayName',
|
||||
translationKey: 'generic.name',
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
sort: ['image', 'displayName'],
|
||||
searchField: 'image',
|
||||
translationKey: 'generic.image',
|
||||
},
|
||||
{
|
||||
name: 'scale',
|
||||
sort: ['scale:desc', 'isGlobalScale:desc', 'displayName'],
|
||||
searchField: null,
|
||||
translationKey: 'stacksPage.table.scale',
|
||||
classNames: 'text-center',
|
||||
width: 100
|
||||
},
|
||||
]
|
||||
|
||||
const ingressHeaders = [
|
||||
{
|
||||
name: 'state',
|
||||
sort: ['sortState','displayName'],
|
||||
searchField: 'displayState',
|
||||
translationKey: 'generic.state',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
sort: ['sortName','id'],
|
||||
searchField: 'displayName',
|
||||
translationKey: 'generic.name',
|
||||
},
|
||||
{
|
||||
name: 'created',
|
||||
sort: ['created','id'],
|
||||
classNames: 'text-right pr-20',
|
||||
searchField: 'created',
|
||||
translationKey: 'generic.created',
|
||||
},
|
||||
]
|
||||
|
||||
const servicesHeaders = [
|
||||
{
|
||||
name: 'state',
|
||||
sort: ['stack.isDefault:desc','stack.displayName','sortState','displayName'],
|
||||
searchField: 'displayState',
|
||||
translationKey: 'generic.state',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
sort: ['stack.isDefault:desc','stack.displayName','displayName','id'],
|
||||
searchField: 'displayName',
|
||||
translationKey: 'generic.name',
|
||||
},
|
||||
{
|
||||
name: 'displayType',
|
||||
sort: ['displayType','displayName','id'],
|
||||
searchField: 'displayType',
|
||||
translationKey: 'generic.type',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
name: 'target',
|
||||
sort: false,
|
||||
searchField: 'displayTargets',
|
||||
translationKey: 'dnsPage.table.target',
|
||||
},
|
||||
]
|
||||
|
||||
const volumesHeaders = [
|
||||
// {
|
||||
// name: 'expand',
|
||||
// sort: false,
|
||||
// searchField: null,
|
||||
// width: 30
|
||||
// },
|
||||
{
|
||||
name: 'state',
|
||||
sort: ['sortState','displayName'],
|
||||
searchField: 'displayState',
|
||||
translationKey: 'generic.state',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
sort: ['displayName','id'],
|
||||
searchField: 'displayName',
|
||||
translationKey: 'volumesPage.claimName.label',
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
sort: ['sizeBytes'],
|
||||
search: ['sizeBytes','displaySize'],
|
||||
translationKey: 'generic.size',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
name: 'volume',
|
||||
sort: ['volume.displayName','displayName','id'],
|
||||
translationKey: 'volumesPage.volume.label',
|
||||
searchField: null,
|
||||
},
|
||||
{
|
||||
name: 'storageClass',
|
||||
sort: ['storageClass.displayName','displayName','id'],
|
||||
translationKey: 'volumesPage.storageClass.label',
|
||||
searchField: null,
|
||||
},
|
||||
]
|
||||
|
||||
const secretsHeaders = [
|
||||
{
|
||||
name: 'state',
|
||||
sort: ['sortState','name','id'],
|
||||
type: 'string',
|
||||
searchField: 'displayState',
|
||||
translationKey: 'generic.state',
|
||||
width: 125,
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
sort: ['name','id'],
|
||||
translationKey: 'generic.name',
|
||||
},
|
||||
{
|
||||
name: 'namespace',
|
||||
translationKey: 'generic.namespace',
|
||||
searchField: 'namespace.displayName',
|
||||
sort: ['namespace.displayName','name','id'],
|
||||
},
|
||||
{
|
||||
name: 'keys',
|
||||
translationKey: 'secretsPage.table.keys',
|
||||
searchField: 'keys',
|
||||
sort: ['firstKey','name','id'],
|
||||
},
|
||||
{
|
||||
name: 'created',
|
||||
translationKey: 'generic.created',
|
||||
sort: ['created:desc','name','id'],
|
||||
searchField: false,
|
||||
type: 'string',
|
||||
width: 150,
|
||||
},
|
||||
]
|
||||
|
||||
export default Controller.extend({
|
||||
// TODO =- expand logic?
|
||||
expandedInstances: [],
|
||||
ingressHeaders: ingressHeaders,
|
||||
servicesHeaders: servicesHeaders,
|
||||
volumesHeaders: volumesHeaders,
|
||||
secretsHeaders: secretsHeaders,
|
||||
ingressSearchText: '',
|
||||
secretsSearchText: '',
|
||||
podsHeaders: podsHeaders,
|
||||
podsSearchText: '',
|
||||
servicesSearchText: '',
|
||||
volumesSearchText: '',
|
||||
sortBy: 'name',
|
||||
extraSearchFields: ['id:prefix', 'displayIp:ip'],
|
||||
extraSearchSubFields: containerSearchFields,
|
||||
actions: {
|
||||
toggleExpand() {
|
||||
// ???
|
||||
},
|
||||
},
|
||||
stdOut: computed('model.app.stdOut', function() {
|
||||
return get(this, 'model.app.status.stdOutput');
|
||||
}),
|
||||
stderr: computed('model.app.stdErr', function() {
|
||||
return get(this, 'model.app.status.stdError');
|
||||
}),
|
||||
|
||||
workloadsAndPods: computed('model.app.workloads', 'model.app.pods', function() {
|
||||
let out = [];
|
||||
out = this.get('model.app.pods').filter(obj => !obj.get('workloadId'));
|
||||
out.pushObjects(this.get('model.app.workloads').slice());
|
||||
return out;
|
||||
}),
|
||||
});
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { get } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Route from '@ember/routing/route';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
export default Route.extend({
|
||||
catalog: service(),
|
||||
store: service(),
|
||||
|
||||
model(params) {
|
||||
const store = get(this, 'store');
|
||||
return hash({
|
||||
app: store.find('app', get(params, 'app_id')),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
<section class="header clearfix">
|
||||
<div class="pull-left">
|
||||
<h1 class="vertical-middle">
|
||||
{{t 'appDetailPage.header' appName=model.app.displayName}}
|
||||
</h1>
|
||||
</div>
|
||||
<div class="vertical-middle"></div>
|
||||
<div class="right-buttons">
|
||||
{{badge-state model=model.app}}
|
||||
{{action-menu model=model.app showPrimary=false classNames="ml-10 pull-right" size="sm"}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
{{#accordion-list as |al expandFn|}}
|
||||
{{#accordion-list-item
|
||||
title=(t 'appDetailPage.output.title')
|
||||
detail=(t 'appDetailPage.output.detail')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<pre class="log-body" style="margin:0; font-size: 80%; color: whitesmoke;">{{stdOut}}</pre>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'appDetailPage.workloads.title')
|
||||
detail=(t 'appDetailPage.workloads.detail')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
{{#sortable-table
|
||||
tableClassNames="double-rows"
|
||||
classNames="grid sortable-table"
|
||||
body=workloadsAndPods
|
||||
searchText=podsSearchText
|
||||
sortBy=sortBy
|
||||
bulkActions=true
|
||||
subRows=true
|
||||
pagingLabel="pagination.workload"
|
||||
subSearchField="pods"
|
||||
extraSearchFields=extraSearchFields
|
||||
extraSearchSubFields=extraSearchSubFields
|
||||
headers=podsHeaders as |sortable kind inst dt|}}
|
||||
{{#if (eq kind "row")}}
|
||||
{{#if (eq inst.type "pod")}}
|
||||
{{pod-row
|
||||
model=inst
|
||||
dt=dt
|
||||
showNode=true
|
||||
expandPlaceholder=true
|
||||
scalePlaceholder=true
|
||||
fullColspan=sortable.fullColspan
|
||||
toggle=(action "toggleExpand" inst.id)
|
||||
expanded=(array-includes expandedInstances inst.id)
|
||||
}}
|
||||
{{else}}
|
||||
{{workload-row
|
||||
model=inst
|
||||
toggle=(action "toggleExpand" inst.id)
|
||||
expanded=(array-includes expandedInstances inst.id)
|
||||
searchText=searchText
|
||||
subMatches=sortable.subMatches
|
||||
fullColspan=sortable.fullColspan
|
||||
dt=dt
|
||||
}}
|
||||
{{/if}}
|
||||
{{else if (eq kind "nomatch")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'containersPage.table.noMatch'}}</td></tr>
|
||||
{{else if (eq kind "norows")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'appDetailPage.workloads.nodata'}}</td></tr>
|
||||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
{{!--
|
||||
--}}
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'appDetailPage.ingress.title')
|
||||
detail=(t 'appDetailPage.ingress.detail')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<section class="pl-0 pr-0">
|
||||
{{#sortable-table
|
||||
classNames="grid sortable-table"
|
||||
body=model.app.ingress
|
||||
searchText=ingressSearchText
|
||||
sortBy=sortBy
|
||||
bulkActions=true
|
||||
pagingLabel="pagination.ingress"
|
||||
subSearchField="instances"
|
||||
headers=ingressHeaders as |sortable kind inst dt|
|
||||
}}
|
||||
{{#if (eq kind "row")}}
|
||||
<tr class="main-row">
|
||||
<td class="row-check" valign="middle" style="padding-top: 2px;">
|
||||
{{check-box nodeId=inst.id}}
|
||||
</td>
|
||||
<td data-title="{{dt.state}}" class="state">
|
||||
{{badge-state model=inst}}
|
||||
</td>
|
||||
<td data-title="{{dt.name}}" class="clip">
|
||||
<a href="{{href-to "ingress" inst.id}}">{{inst.displayName}}</a>
|
||||
</td>
|
||||
<td data-title="{{dt.created}}" class="text-right pr-20">
|
||||
{{date-calendar inst.created}}
|
||||
</td>
|
||||
<td data-title="{{dt.actions}}" class="actions">
|
||||
{{action-menu model=inst}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else if (eq kind "nomatch")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'ingressPage.table.noMatch'}}</td></tr>
|
||||
{{else if (eq kind "norows")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'appDetailPage.ingress.nodata'}}</td></tr>
|
||||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
</section>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'appDetailPage.services.title')
|
||||
detail=(t 'appDetailPage.services.detail')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
{{#sortable-table
|
||||
classNames="grid sortable-table"
|
||||
body=model.app.services
|
||||
searchText=servicesSearchText
|
||||
sortBy=sortBy
|
||||
bulkActions=true
|
||||
pagingLabel="pagination.dnsRecord"
|
||||
headers=servicesHeaders as |sortable kind inst dt|
|
||||
}}
|
||||
{{#if (eq kind "row")}}
|
||||
{{dns-row
|
||||
model=inst
|
||||
searchText=searchText
|
||||
fullColspan=sortable.fullColspan
|
||||
dt=dt
|
||||
}}
|
||||
{{else if (eq kind "nomatch")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted pt-20 pb-20">{{t 'dnsPage.noMatch'}}</td></tr>
|
||||
{{else if (eq kind "norows")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'appDetailPage.services.nodata'}}</td></tr>
|
||||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'appDetailPage.volumes.title')
|
||||
detail=(t 'appDetailPage.volumes.detail')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
<section class="pl-0 pr-0">
|
||||
{{#sortable-table
|
||||
classNames="grid sortable-table"
|
||||
body=model.app.volumes
|
||||
searchText=volumesSearchText
|
||||
sortBy=sortBy
|
||||
bulkActions=true
|
||||
pagingLabel="pagination.volume"
|
||||
headers=volumesHeaders as |sortable kind obj dt|
|
||||
}}
|
||||
{{#if (eq kind "row")}}
|
||||
<tr class="main-row">
|
||||
<td class="row-check" valign="middle" style="padding-top: 2px;">
|
||||
{{check-box nodeId=obj.id}}
|
||||
</td>
|
||||
<td data-title="{{dt.state}}">
|
||||
{{badge-state model=obj}}
|
||||
</td>
|
||||
<td data-title="{{dt.name}}">
|
||||
<a href="{{href-to "volumes.detail" obj.id}}">{{obj.displayName}}</a>
|
||||
</td>
|
||||
<td data-title="{{dt.size}}">
|
||||
{{obj.displaySize}}
|
||||
</td>
|
||||
<td data-title="{{dt.volume}}">
|
||||
{{#if obj.persistentVolume}}
|
||||
<a href="{{href-to "authenticated.cluster.storage.persistent-volumes.detail" scope.currentCluster.id obj.persistentVolume.id}}">
|
||||
{{obj.persistentVolume.displayName}}
|
||||
</a>
|
||||
{{else}}
|
||||
<span class="text-muted">–</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-title="{{dt.storageClass}}">
|
||||
{{#if obj.storageClass}}
|
||||
<a href="{{href-to "authenticated.cluster.storage.classes.detail" scope.currentCluster.id obj.storageClass.id}}">
|
||||
{{obj.storageClass.displayName}}
|
||||
</a>
|
||||
{{else}}
|
||||
<span class="text-muted">–</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-title="{{dt.actions}}" class="actions">
|
||||
{{action-menu model=obj}}
|
||||
</td>
|
||||
</tr>
|
||||
{{else if (eq kind "nomatch")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'volumesPage.noMatch'}}</td></tr>
|
||||
{{else if (eq kind "norows")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'appDetailPage.volumes.nodata'}}</td></tr>
|
||||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
</section>
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{#accordion-list-item
|
||||
title=(t 'appDetailPage.secrets.title')
|
||||
detail=(t 'appDetailPage.secrets.detail')
|
||||
expandAll=al.expandAll
|
||||
expand=(action expandFn)
|
||||
expandOnInit=true
|
||||
}}
|
||||
{{#sortable-table
|
||||
classNames="grid sortable-table"
|
||||
body=model.app.secrets
|
||||
sortBy=sortBy
|
||||
bulkActions=true
|
||||
searchText=secretsSearchText
|
||||
headers=secretsHeaders as |sortable kind row dt|
|
||||
}}
|
||||
{{#if (eq kind "row")}}
|
||||
{{secret-row model=row dt=dt}}
|
||||
{{else if (eq kind "nomatch")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted pt-20 pb-20">{{t 'secretsPage.index.noMatch'}}</td></tr>
|
||||
{{else if (eq kind "norows")}}
|
||||
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'appDetailPage.secrets.nodata'}}</td></tr>
|
||||
{{/if}}
|
||||
{{/sortable-table}}
|
||||
{{/accordion-list-item}}
|
||||
|
||||
{{/accordion-list}}
|
||||
</section>
|
||||
|
|
@ -1,14 +1,27 @@
|
|||
import Resource from 'ember-api-store/models/resource';
|
||||
import { hasMany } from 'ember-api-store/utils/denormalize';
|
||||
import { hasMany, reference } from 'ember-api-store/utils/denormalize';
|
||||
import { computed, get } from '@ember/object';
|
||||
import { parseHelmExternalId } from 'ui/utils/parse-externalid';
|
||||
import StateCounts from 'ui/mixins/state-counts';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
const App = Resource.extend(StateCounts, {
|
||||
catalog: service(),
|
||||
router: service(),
|
||||
pods: hasMany('installNamespace', 'pod', 'namespaceId'),
|
||||
catalog: service(),
|
||||
router: service(),
|
||||
// pods: hasMany('id', 'pod', 'appId'),
|
||||
// services: hasMany('id', 'service', 'appId'),
|
||||
// workloads: hasMany('id', 'workload', 'appId'),
|
||||
// secrets: hasMany('id', 'secret', 'appId'),
|
||||
// ingress: hasMany('id', 'ingress', 'appId'),
|
||||
// volumes: hasMany('id', 'persistentVolumeClaim', 'appId'),
|
||||
pods: hasMany('installNamespace', 'pod', 'namespaceId'),
|
||||
services: hasMany('installNamespace', 'service', 'namespaceId'),
|
||||
workloads: hasMany('installNamespace', 'workload', 'namespaceId'),
|
||||
secrets: hasMany('installNamespace', 'secret', 'namespaceId'),
|
||||
ingress: hasMany('installNamespace', 'ingress', 'namespaceId'),
|
||||
volumes: hasMany('installNamespace', 'persistentVolumeClaim', 'namespaceId'),
|
||||
namespace: reference('namespaceId', 'namespace', 'clusterStore'),
|
||||
//workloads on pod
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
|
|
|||
|
|
@ -150,11 +150,13 @@ Router.map(function() {
|
|||
// Catalog
|
||||
this.route('apps-tab', {path: '/apps', resetNamespace: true}, function() {
|
||||
this.route('index', {path: '/'});
|
||||
this.route('detail', {path: '/:app_id'});
|
||||
|
||||
this.route('catalog-tab', {path: '/catalog', resetNamespace: true}, function() {
|
||||
this.route('index', {path: '/'});
|
||||
this.route('launch', {path: '/:template'});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// Resources
|
||||
|
|
|
|||
|
|
@ -4,71 +4,71 @@ import Controller from '@ember/controller';
|
|||
import Errors from 'ui/utils/errors';
|
||||
import C from 'ui/utils/constants';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import { computed, observer } from '@ember/object';
|
||||
import { get, set, computed, observer } from '@ember/object';
|
||||
|
||||
var PLAIN_PORT = 389;
|
||||
var TLS_PORT = 636;
|
||||
|
||||
export default Controller.extend({
|
||||
access: service(),
|
||||
settings: service(),
|
||||
access: service(),
|
||||
settings: service(),
|
||||
|
||||
confirmDisable: false,
|
||||
errors: null,
|
||||
testing: false,
|
||||
errors: null,
|
||||
testing: false,
|
||||
|
||||
providerName: 'ldap.providerName.ad',
|
||||
userType: C.PROJECT.TYPE_LDAP_USER,
|
||||
groupType: C.PROJECT.TYPE_LDAP_GROUP,
|
||||
providerName: 'ldap.providerName.ad',
|
||||
userType: C.PROJECT.TYPE_LDAP_USER,
|
||||
groupType: C.PROJECT.TYPE_LDAP_GROUP,
|
||||
|
||||
addUserInput: '',
|
||||
addOrgInput: '',
|
||||
addUserInput: '',
|
||||
addOrgInput: '',
|
||||
|
||||
username: '',
|
||||
password: '',
|
||||
isEnabled: alias('model.activeDirectory.enabled'),
|
||||
adConfig: alias('model.activeDirectory'),
|
||||
username: '',
|
||||
password: '',
|
||||
isEnabled: alias('model.activeDirectory.enabled'),
|
||||
adConfig: alias('model.activeDirectory'),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
if (this.get('adConfig')){
|
||||
if (get(this, 'adConfig')){
|
||||
this.tlsChanged();
|
||||
}
|
||||
},
|
||||
createDisabled: computed('username.length','password.length', function() {
|
||||
return !this.get('username.length') || !this.get('password.length');
|
||||
return !get(this, 'username.length') || !get(this, 'password.length');
|
||||
}),
|
||||
|
||||
numUsers: computed('adConfig.allowedIdentities.@each.externalIdType','userType','groupType', function() {
|
||||
return (this.get('adConfig.allowedIdentities')||[]).filterBy('externalIdType', this.get('userType')).get('length');
|
||||
return ( get(this, 'adConfig.allowedPrincipalIds') || [] ).filter(principal => principal.includes(C.PROJECT.TYPE_ACTIVE_DIRECTORY_USER)).get('length');
|
||||
}),
|
||||
|
||||
numGroups: computed('adConfig.allowedIdentities.@each.externalIdType','userType','groupType', function() {
|
||||
return (this.get('adConfig.allowedIdentities')||[]).filterBy('externalIdType', this.get('groupType')).get('length');
|
||||
return ( get(this, 'adConfig.allowedPrincipalIds') || [] ).filter(principal => principal.includes(C.PROJECT.TYPE_ACTIVE_DIRECTORY_GROUP)).get('length');
|
||||
}),
|
||||
|
||||
configServers: computed('adConfig.servers', {
|
||||
get() {
|
||||
return (this.get('adConfig.servers')||[]).join(',');
|
||||
return (get(this, 'adConfig.servers')||[]).join(',');
|
||||
},
|
||||
set(key, value) {
|
||||
this.set('adConfig.servers', value.split(','));
|
||||
set(this, 'adConfig.servers', value.split(','));
|
||||
return value;
|
||||
}
|
||||
}),
|
||||
|
||||
tlsChanged: observer('adConfig.tls', function() {
|
||||
var on = (this.get('adConfig.tls')||false);
|
||||
var port = parseInt(this.get('adConfig.port'),10);
|
||||
var on = (get(this, 'adConfig.tls')||false);
|
||||
var port = parseInt(get(this, 'adConfig.port'),10);
|
||||
|
||||
if ( on && port === PLAIN_PORT )
|
||||
{
|
||||
this.set('adConfig.port', TLS_PORT);
|
||||
set(this, 'adConfig.port', TLS_PORT);
|
||||
}
|
||||
else if ( !on /* && port === TLS_PORT */ ) // TODO 2.0
|
||||
{
|
||||
this.set('adConfig.port', PLAIN_PORT);
|
||||
this.set('adConfig.tls', false);
|
||||
set(this, 'adConfig.port', PLAIN_PORT);
|
||||
set(this, 'adConfig.tls', false);
|
||||
}
|
||||
}),
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ export default Controller.extend({
|
|||
test: function() {
|
||||
this.send('clearError');
|
||||
|
||||
var model = this.get('adConfig');
|
||||
var model = get(this, 'adConfig');
|
||||
model.setProperties({
|
||||
accessMode: 'unrestricted',
|
||||
});
|
||||
|
|
@ -84,16 +84,16 @@ export default Controller.extend({
|
|||
var errors = model.validationErrors();
|
||||
if ( errors.get('length') )
|
||||
{
|
||||
this.set('errors', errors);
|
||||
set(this, 'errors', errors);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.set('testing', true);
|
||||
set(this, 'testing', true);
|
||||
model.doAction('testAndApply', {
|
||||
activeDirectoryConfig: model,
|
||||
enabled: true,
|
||||
username: this.get('username'),
|
||||
password: this.get('password'),
|
||||
username: get(this, 'username'),
|
||||
password: get(this, 'password'),
|
||||
}).then( () => {
|
||||
this.send('waitAndRefresh');
|
||||
}).catch((err) => {
|
||||
|
|
@ -111,25 +111,25 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
promptDisable: function() {
|
||||
this.set('confirmDisable', true);
|
||||
set(this, 'confirmDisable', true);
|
||||
later(this, function() {
|
||||
this.set('confirmDisable', false);
|
||||
set(this, 'confirmDisable', false);
|
||||
}, 10000);
|
||||
},
|
||||
|
||||
gotError: function(err) {
|
||||
this.set('errors', [Errors.stringify(err)]);
|
||||
this.set('testing', false);
|
||||
set(this, 'errors', [Errors.stringify(err)]);
|
||||
set(this, 'testing', false);
|
||||
},
|
||||
|
||||
clearError: function() {
|
||||
this.set('errors', null);
|
||||
set(this, 'errors', null);
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
this.send('clearError');
|
||||
|
||||
var model = this.get('adConfig');
|
||||
var model = get(this, 'adConfig');
|
||||
model.setProperties({
|
||||
enabled: false,
|
||||
});
|
||||
|
|
@ -140,7 +140,7 @@ export default Controller.extend({
|
|||
}).catch((err) => {
|
||||
this.send('gotError', err);
|
||||
}).finally(() => {
|
||||
this.set('confirmDisable', false);
|
||||
set(this, 'confirmDisable', false);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { once, later } from '@ember/runloop';
|
|||
import { alias } from '@ember/object/computed';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Controller from '@ember/controller';
|
||||
import C from 'ui/utils/constants';
|
||||
|
||||
export default Controller.extend({
|
||||
github: service(),
|
||||
|
|
@ -52,13 +53,12 @@ export default Controller.extend({
|
|||
}),
|
||||
|
||||
numUsers: computed('githubConfig.allowedPrincipals.@each.externalIdType','wasRestricted', function() {
|
||||
return 3; //TODO
|
||||
// return get(this, 'githubConfig.principals').filterBy('externalIdType',C.PROJECT.TYPE_GITHUB_USER).get('length');
|
||||
return ( get(this, 'githubConfig.allowedPrincipalIds') || []).filter(principal => principal.includes(C.PROJECT.TYPE_GITHUB_USER)).get('length');
|
||||
}),
|
||||
|
||||
numOrgs: computed('githubConfig.allowedPrincipals.@each.externalIdType','wasRestricted',function() {
|
||||
return 4; //TODO
|
||||
// return get(this, 'githubConfig.principals').filterBy('externalIdType',C.PROJECT.TYPE_GITHUB_ORG).get('length');
|
||||
|
||||
return ( get(this, 'githubConfig.allowedPrincipalIds') || []).filter(principal => principal.includes(C.PROJECT.TYPE_GITHUB_ORG)).get('length');
|
||||
}),
|
||||
|
||||
destinationUrl: computed(function() {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
<div class="row">
|
||||
<div class="col span-4">
|
||||
<h3>{{t 'ldap.accessEnabled.general.header'}}</h3>
|
||||
<div><b>{{t 'ldap.accessEnabled.general.server'}} </b> <span class="text-muted">{{adConfig.server}}:{{adConfig.port}}</span></div>
|
||||
<div><b>{{t 'ldap.accessEnabled.general.server'}} </b> <span class="text-muted">{{adConfig.servers.firstObject}}:{{adConfig.port}}</span></div>
|
||||
<div><b>{{t 'ldap.accessEnabled.general.tls'}} </b> <span class="text-muted">{{if adConfig.tls "Yes" "No"}}</span></div>
|
||||
<div><b>{{t 'ldap.accessEnabled.general.serviceAccount'}} </b> <span class="text-muted">{{adConfig.serviceAccountUsername}}</span></div>
|
||||
{{#unless isOpenLdap}}
|
||||
|
|
|
|||
|
|
@ -1,110 +0,0 @@
|
|||
import { get, set, computed } from '@ember/object';
|
||||
import { next } from '@ember/runloop';
|
||||
import { inject as service } from '@ember/service';
|
||||
import Component from '@ember/component';
|
||||
import C from 'ui/utils/constants';
|
||||
|
||||
export default Component.extend({
|
||||
access: service(),
|
||||
cookies: service(),
|
||||
isCaas: computed('app.mode', function() {
|
||||
return this.get('app.mode') === 'caas' ? true : false;
|
||||
}),
|
||||
waiting: null,
|
||||
|
||||
username: null,
|
||||
rememberUsername: false,
|
||||
password: null,
|
||||
shown: false,
|
||||
provider: null,
|
||||
readableProvider: null,
|
||||
|
||||
actions: {
|
||||
showLocal() {
|
||||
this.toggleProperty('shown');
|
||||
next(this, 'focusSomething');
|
||||
},
|
||||
authenticate: function() {
|
||||
const username = get(this, 'username');
|
||||
let password = get(this, 'password');
|
||||
const remember = get(this, 'rememberUsername');
|
||||
|
||||
if (password && get(this, 'provider') === 'local') {
|
||||
password = password.trim();
|
||||
}
|
||||
|
||||
const code = {
|
||||
username: username,
|
||||
password: password,
|
||||
};
|
||||
|
||||
if ( remember ) {
|
||||
if (get(this, 'provider') === 'local') {
|
||||
get(this, 'cookies').setWithOptions(C.COOKIE.USERNAME, username, {expire: 365, secure: 'auto'});
|
||||
} else {
|
||||
get(this, 'cookies').setWithOptions(`${get(this, 'provider').toUpperCase()}-USERNAME`, username, {expire: 365, secure: 'auto'});
|
||||
}
|
||||
} else {
|
||||
get(this, 'cookies').remove(C.COOKIE.USERNAME);
|
||||
}
|
||||
|
||||
set(this, 'password', '');
|
||||
if ( get(this,'access.providers') ) {
|
||||
this.sendAction('action', get(this, 'provider'), code);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
||||
var username = null;
|
||||
if (get(this, 'provider') === 'local') {
|
||||
username = get(this, `cookies.${C.COOKIE.USERNAME}`);
|
||||
} else {
|
||||
username = get(this, `cookies.${get(this, 'provider').toUpperCase()}-USERNAME`);
|
||||
}
|
||||
|
||||
if ( username ) {
|
||||
set(this, 'username', username);
|
||||
set(this, 'rememberUsername', true);
|
||||
}
|
||||
|
||||
if (get(this, 'provider')) {
|
||||
let pv = null;
|
||||
switch(get(this, 'provider')) {
|
||||
case 'activedirectory':
|
||||
pv = 'Active Directory';
|
||||
break;
|
||||
case 'local':
|
||||
default:
|
||||
pv = 'Local Auth';
|
||||
break;
|
||||
}
|
||||
|
||||
set(this, 'readableProvider', pv);
|
||||
|
||||
// console.log(this.get('provider'));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
focusSomething() {
|
||||
if ( this.isDestroyed || this.isDestroying ) {
|
||||
return;
|
||||
}
|
||||
|
||||
let elem = this.$('#login-username-ad');
|
||||
if ( get(this, 'username') ) {
|
||||
elem = this.$('#login-password-ad');
|
||||
}
|
||||
|
||||
if ( elem && elem[0] ) {
|
||||
elem[0].focus();
|
||||
}
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
next(this, 'focusSomething');
|
||||
},
|
||||
});
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
{{#if shown}}
|
||||
<form {{action "authenticate" on="submit"}} class="text-left mt-10">
|
||||
<div class="mt-20">
|
||||
<div>
|
||||
{{#if isCaas}}
|
||||
<label class="acc-label">{{t 'loginUserPass.caasLabel'}}</label>
|
||||
{{else}}
|
||||
<label class="acc-label">{{t 'loginUserPass.userLabel'}}</label>
|
||||
{{/if}}
|
||||
<div class="pull-right">
|
||||
<label class="acc-label">{{t 'loginUserPass.remember'}} {{input type="checkbox" checked=rememberUsername}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{input type="text" id="login-username-ad" autocomplete="username" class="form-control login-user" value=username placeholder=(t 'loginUserPass.userPlaceholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-15 pb-15">
|
||||
<label class="acc-label">{{t 'loginUserPass.passwordLabel'}}</label>
|
||||
<div>
|
||||
{{input id="login-password-ad" autocomplete="password" type="password" class="form-control login-pass" value=password}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-center">
|
||||
<button disabled={{waiting}} class="btn bg-primary" {{action "authenticate"}}>
|
||||
{{#if waiting}}
|
||||
<i class="icon icon-spinner icon-spin"></i> {{t 'loginUserPass.loggingInLabel'}}
|
||||
{{else}}
|
||||
{{t 'loginUserPass.loginLabel' provider=readableProvider}}
|
||||
{{/if}}
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
{{else}}
|
||||
{{#if (eq provider 'local')}}
|
||||
<a class="link-text text-small mt-10 hand" {{action 'showLocal'}}>{{t 'loginUserPass.local'}}</a>
|
||||
{{else}}
|
||||
<a class="btn bg-primary" {{action 'showLocal'}}> <i class="icon icon-key"></i> {{t 'loginUserPass.provider' kind=readableProvider}}</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
|
@ -108,4 +108,9 @@ export default Component.extend({
|
|||
didInsertElement() {
|
||||
next(this, 'focusSomething');
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
set(this, 'shown', false);
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{input type="text" id="login-username" autocomplete="username" class="form-control login-user" value=username placeholder=(t 'loginUserPass.userPlaceholder')}}
|
||||
{{input type="text" id=(concat "login-username-" provider) autocomplete="username" class="form-control login-user" value=username placeholder=(t 'loginUserPass.userPlaceholder')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-15 pb-15">
|
||||
<label class="acc-label">{{t 'loginUserPass.passwordLabel'}}</label>
|
||||
<div>
|
||||
{{input id="login-password" autocomplete="password" type="password" class="form-control login-pass" value=password}}
|
||||
{{input id=(concat "login-password-" provider) autocomplete="password" type="password" class="form-control login-pass" value=password}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ export default Controller.extend({
|
|||
isForbidden: equal('errorCode', '403'),
|
||||
|
||||
waiting: false,
|
||||
adWaiting: false,
|
||||
localWaiting: false,
|
||||
shibbolethWaiting: false,
|
||||
errorMsg: null,
|
||||
errorCode: null,
|
||||
resetPassword: false,
|
||||
|
|
@ -76,7 +79,6 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
actions: {
|
||||
|
||||
started() {
|
||||
setProperties(this, {
|
||||
'waiting': true,
|
||||
|
|
@ -84,6 +86,27 @@ export default Controller.extend({
|
|||
});
|
||||
},
|
||||
|
||||
waiting(provider) {
|
||||
// setProperties(this, {
|
||||
// 'waiting': true,
|
||||
// 'errorMsg': null,
|
||||
// });
|
||||
set(this, 'errorMsg', null);
|
||||
switch (provider) {
|
||||
case 'local':
|
||||
this.toggleProperty('localWaiting');
|
||||
break;
|
||||
case 'activedirectory':
|
||||
this.toggleProperty('adWaiting');
|
||||
break;
|
||||
case 'shibboleth':
|
||||
this.toggleProperty('shibbolethWaiting');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
complete(success) {
|
||||
if (success) {
|
||||
this.shouldSetServerUrl().then((proceed) => {
|
||||
|
|
@ -102,7 +125,7 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
authenticate(provider, code) {
|
||||
this.send('started');
|
||||
this.send('waiting', provider);
|
||||
|
||||
later(() => {
|
||||
get(this, 'access').login(provider, code).then((user) => {
|
||||
|
|
@ -118,9 +141,10 @@ export default Controller.extend({
|
|||
get(this, 'access').set('userCode', null);
|
||||
get(this, 'access').set('firstLogin', false);
|
||||
this.send('complete', true);
|
||||
this.send('waiting', provider);
|
||||
}
|
||||
}).catch((err) => {
|
||||
set(this, 'waiting', false);
|
||||
this.send('waiting', provider);
|
||||
|
||||
if ( err && err.status === 401 ) {
|
||||
let key = 'loginPage.error.authFailed'
|
||||
|
|
|
|||
|
|
@ -54,8 +54,13 @@ export default Route.extend({
|
|||
|
||||
resetController(controller, isExisting /*, transition*/ ) {
|
||||
if (isExisting) {
|
||||
controller.set('changePassword', false);
|
||||
controller.set('waiting',false);
|
||||
controller.setProperties({
|
||||
changePassword: false,
|
||||
waiting: false,
|
||||
adWaiting: false,
|
||||
shibbolethWaiting: false,
|
||||
localWaiting: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<br/>
|
||||
{{login-shibboleth
|
||||
action="started"
|
||||
waiting=waiting
|
||||
waiting=shibbolethWaiting
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
|
|
@ -25,23 +25,23 @@
|
|||
{{/if}}
|
||||
|
||||
{{#if isActiveDirectory}}
|
||||
{{login-ad
|
||||
classNames="row"
|
||||
{{login-user-pass
|
||||
action="authenticate"
|
||||
waiting=waiting
|
||||
shown=true
|
||||
classNames="row"
|
||||
provider="activedirectory"
|
||||
shown=true
|
||||
waiting=adWaiting
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isLocal}}
|
||||
{{login-user-pass
|
||||
classNames="row"
|
||||
action="authenticate"
|
||||
waiting=waiting
|
||||
shown=onlyLocal
|
||||
classNames="row"
|
||||
onlyLocal=onlyLocal
|
||||
provider="local"
|
||||
shown=onlyLocal
|
||||
waiting=localWaiting
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import C from 'shared/utils/constants';
|
|||
import EmberObject from '@ember/object'
|
||||
import { get } from '@ember/object';
|
||||
import { /* parseExternalId, */ parseHelmExternalId } from 'ui/utils/parse-externalid';
|
||||
import { all } from 'rsvp';
|
||||
import { all, allSettled } from 'rsvp';
|
||||
|
||||
const RANCHER_VERSION = 'rancherVersion';
|
||||
const DEFAULT_BASE = 'kubernetes';
|
||||
|
|
@ -47,7 +47,7 @@ export default Service.extend({
|
|||
deps.push(this.fetchTemplate(extInfo.templateId, false));
|
||||
});
|
||||
|
||||
return all(deps);
|
||||
return allSettled(deps);
|
||||
},
|
||||
|
||||
fetchCatalogs(opts) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export default Component.extend({
|
|||
questions: alias('selectedTemplate.questions'),
|
||||
pasteOrUpload: false,
|
||||
accept : '.yml, .yaml',
|
||||
showHeader: true,
|
||||
_boundChange : null,
|
||||
didInsertElement() {
|
||||
this.set('_boundChange', (event) => { this.change(event); });
|
||||
|
|
|
|||
|
|
@ -3,8 +3,13 @@
|
|||
<button class="btn btn-sm bg-primary" {{action 'showPaste'}}>{{t 'generic.paste'}} <span class="icon icon-copy"></span></button>
|
||||
<button class="btn btn-sm bg-primary" {{action 'upload'}}>{{t 'generic.upload'}} <span class="icon icon-upload"></span></button>
|
||||
</div>
|
||||
<h4 class="mb-0">{{t 'inputAnswers.config'}}</h4>
|
||||
<span class="protip">{{t 'inputAnswers.protip'}}</span>
|
||||
<div>
|
||||
{{#if showHeader}}
|
||||
<h4 class="mb-0">{{t 'inputAnswers.config'}}</h4>
|
||||
<span class="protip">{{t 'inputAnswers.protip'}}</span>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
<div class="mt-20">
|
||||
{{#if pasteOrUpload}}
|
||||
{{textarea-autogrow
|
||||
|
|
|
|||
|
|
@ -5,9 +5,19 @@
|
|||
<div class="stack-info-row box">
|
||||
<div class="stack-info-top row">
|
||||
<div class="col">
|
||||
{{model.displayName}}
|
||||
{{#link-to "apps-tab.detail" model.id}}
|
||||
{{model.displayName}}
|
||||
{{/link-to}}
|
||||
</div>
|
||||
<div class="col text-right pull-right">
|
||||
{{#upgrade-btn model=model classNames="btn-xs " as |btn|}}
|
||||
{{#if btn.model.externalIdInfo.version}}
|
||||
{{t (concat 'upgradeBtn.status.' btn.upgradeStatus)}}
|
||||
<span class="text-small">({{btn.latestVersion}})</span>
|
||||
{{else}}
|
||||
{{t (concat 'upgradeBtn.status.' btn.upgradeStatus)}}
|
||||
{{/if}}
|
||||
{{/upgrade-btn}}
|
||||
{{badge-state model=model classNames="btn-xs"}}
|
||||
{{action-menu model=model classNames="inline-block"}}
|
||||
</div>
|
||||
|
|
@ -25,17 +35,15 @@
|
|||
{{model.pods.length}}
|
||||
</small>
|
||||
</div>
|
||||
{{#upgrade-btn model=model classNames="btn-sm" as |btn|}}
|
||||
{{model.externalIdInfo.version}}
|
||||
{{#if btn.model.externalIdInfo.version}}
|
||||
{{t (concat 'upgradeBtn.status.' btn.upgradeStatus)}}
|
||||
<span class="text-small">({{btn.latestVersion}})</span>
|
||||
{{else}}
|
||||
{{t (concat 'upgradeBtn.status.' btn.upgradeStatus)}}
|
||||
<div class="col">
|
||||
{{#if model.workloads}}
|
||||
<div class="clip text-small">
|
||||
{{#each model.workloads as |workload|}}
|
||||
{{workload.displayEndpoints}}
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/upgrade-btn}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if expanded}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
@ -121,7 +121,7 @@ export default Component.extend(NewOrEdit, {
|
|||
value: file.name
|
||||
}
|
||||
});
|
||||
files.addObject({label: 'answers', value: 'answers'});
|
||||
files.addObject({label: 'answers.yaml', value: 'answers'});
|
||||
return files.sortBy('label');
|
||||
}),
|
||||
|
||||
|
|
|
|||
|
|
@ -8,131 +8,134 @@
|
|||
</section>
|
||||
{{/if}}
|
||||
|
||||
<section class="{{sectionClass}} row">
|
||||
<div class="col span-3">
|
||||
{{#if templateResource.links.icon}}
|
||||
<img src={{templateResource.links.icon}} alt={{templateResource.name}} class="mr-20" style="height:75px;max-width: 100%;">
|
||||
{{/if}}
|
||||
|
||||
<div>
|
||||
<small><strong>{{t 'newCatalog.catalog'}}</strong> <span class="text-capitalize">{{templateResource.catalogId}}</span></small>
|
||||
<div class="accordion"> {{!-- container-section --}}
|
||||
<div class="accordion-header"> {{!-- header-section --}}
|
||||
<div class="title">
|
||||
<span class="m-0 ">{{t 'newCatalog.appInfo'}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<small><strong>{{t 'newCatalog.kind'}}</strong> <span class="text-capitalize">{{templateKind}}</span></small>
|
||||
</div>
|
||||
<div class="accordion-content row"> {{!-- content-section --}}
|
||||
<div class="col span-12 text-center">
|
||||
{{#if templateResource.links.icon}}
|
||||
<img src={{templateResource.links.icon}} alt={{templateResource.name}} class="mr-20" style="height:75px;max-width: 100%;">
|
||||
{{/if}}
|
||||
</div>
|
||||
<div>
|
||||
<small><strong>{{t 'newCatalog.category'}}</strong> {{join-array templateResource.categoryArray}}</small>
|
||||
</div>
|
||||
{{#if (eq templateResource.certifiedType 'rancher')}}
|
||||
<small><strong>{{t 'newCatalog.support'}} </strong>{{t 'newCatalog.official'}}</small>
|
||||
{{#if readmeContent}}
|
||||
<div class="col span-12" style="overflow-y: auto; max-height: 500px;">
|
||||
{{marked-down markdown=readmeContent}}
|
||||
</div>
|
||||
{{else}}
|
||||
<small><strong>{{t 'newCatalog.support'}} </strong>{{t 'newCatalog.maintainedBy'}}</small>
|
||||
{{/if}}
|
||||
{{#if templateResource.maintainer}}
|
||||
<div>
|
||||
<small><strong>{{t 'newCatalog.maintainer'}}</strong> {{templateResource.maintainer}}</small>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if templateResource.license}}
|
||||
<div>
|
||||
<small><strong>{{t 'newCatalog.license'}}</strong> {{templateResource.license}}</small>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if templateResource.links.project}}
|
||||
<small class="force-wrap"><strong>{{t 'newCatalog.url'}}</strong> <a href="{{templateResource.cleanProjectUrl}}" target="_blank">{{templateResource.cleanProjectUrl}}</a></small>
|
||||
<h2 class="mb-10">
|
||||
{{t (if editing titleUpgrade titleAdd) name=templateResource.name}}
|
||||
</h2>
|
||||
<p>{{templateResource.description}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if readmeContent}}
|
||||
<div class="col span-9" style="overflow-y: auto; max-height: 500px;">
|
||||
{{marked-down markdown=readmeContent}}
|
||||
</div>
|
||||
{{else}}
|
||||
<h2 class="mb-10">
|
||||
{{t (if editing titleUpgrade titleAdd) name=templateResource.name}}
|
||||
</h2>
|
||||
<p>{{templateResource.description}}</p>
|
||||
{{/if}}
|
||||
</section>
|
||||
<section class="{{sectionClass}}">
|
||||
<h4>{{t 'newCatalog.newApp'}}</h4>
|
||||
{{form-name-description
|
||||
model=catalogApp
|
||||
nameRequired=true
|
||||
descriptionShow=false
|
||||
nameDisabled=showName
|
||||
}}
|
||||
</div>
|
||||
|
||||
{{#if showName}}
|
||||
{{#advanced-section}}
|
||||
<hr class="mt-20 mb-20"/>
|
||||
|
||||
{{form-namespace
|
||||
namespace=primaryResource
|
||||
mode='reuse'
|
||||
errors=namespaceErrors
|
||||
}}
|
||||
{{/advanced-section}}
|
||||
{{/if}}
|
||||
|
||||
</section>
|
||||
|
||||
<section class="{{sectionClass}}">
|
||||
<h4>{{t 'newCatalog.templateVersion'}}</h4>
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=sortedVersions
|
||||
prompt="newCatalog.version.prompt"
|
||||
localizedPrompt=true
|
||||
optionLabelPath="version"
|
||||
optionValuePath="link"
|
||||
value=selectedTemplateUrl
|
||||
disabled=getTemplate.isRunning
|
||||
}}
|
||||
<p class="text-info">{{t (if editing selectVersionUpgrade selectVersionAdd)}}</p>
|
||||
<div class="accordion">
|
||||
<div class="accordion-header">
|
||||
<div class="title">
|
||||
<span class="m-0 ">{{t 'newCatalog.newApp'}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="accordion-content row">
|
||||
<div class="row">
|
||||
<div class="col span-6">
|
||||
{{form-name-description
|
||||
model=catalogApp
|
||||
nameRequired=true
|
||||
descriptionShow=false
|
||||
nameDisabled=showName
|
||||
bothColClass="col span-12"
|
||||
colClass="col span-12"
|
||||
}}
|
||||
</div>
|
||||
<div class="col span-6" style="padding-top: 6px;"> {{!-- matches styles of form-name-description --}}
|
||||
<label for="" class="acc-label">{{t 'newCatalog.templateVersion'}}</label>
|
||||
{{new-select
|
||||
classNames="form-control"
|
||||
content=sortedVersions
|
||||
prompt="newCatalog.version.prompt"
|
||||
localizedPrompt=true
|
||||
optionLabelPath="version"
|
||||
optionValuePath="link"
|
||||
value=selectedTemplateUrl
|
||||
disabled=getTemplate.isRunning
|
||||
}}
|
||||
<p class="text-info">{{t (if editing selectVersionUpgrade selectVersionAdd)}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col span-12">
|
||||
{{#if showName}}
|
||||
{{#advanced-section}}
|
||||
<hr class="mt-20 mb-20"/>
|
||||
|
||||
<section class="{{sectionClass}}">
|
||||
{{#if getTemplate.isRunning}}
|
||||
{{form-namespace
|
||||
namespace=primaryResource
|
||||
mode='reuse'
|
||||
errors=namespaceErrors
|
||||
}}
|
||||
{{/advanced-section}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if getTemplate.isRunning}}
|
||||
<section class="row">
|
||||
<div class="text-center">
|
||||
<i class="icon icon-spinner icon-spin" style="font-size:36px;"></i>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if selectedTemplateModel}}
|
||||
{{#if (eq templateKind 'native')}}
|
||||
{{input-answers
|
||||
selectedTemplate=selectedTemplateModel
|
||||
}}
|
||||
{{else}}
|
||||
<h4>{{t 'newCatalog.helm.label'}}</h4>
|
||||
<div class="span-12">
|
||||
{{#if selectedTemplateModel.questions}}
|
||||
{{input-answers
|
||||
selectedTemplate=selectedTemplateModel
|
||||
}}
|
||||
</section>
|
||||
{{else}}
|
||||
<div class="accordion">
|
||||
<div class="accordion-header">
|
||||
<div class="title">
|
||||
{{#if (or (eq templateKind 'native') selectedTemplateModel.questions)}}
|
||||
<span class="m-0 block">{{t 'inputAnswers.config'}}</span>
|
||||
<span class="help-block">{{t 'inputAnswers.protip'}}</span>
|
||||
{{else}}
|
||||
{{form-key-value
|
||||
initialMap=catalogApp.answers
|
||||
changed=(action (mut catalogApp.answers))
|
||||
allowEmptyValue=false
|
||||
editing=true
|
||||
header=(t 'newCatalog.answers.label')
|
||||
addActionLabel="newCatalog.answers.addAction"
|
||||
keyLabel="newContainer.environment.keyLabel"
|
||||
keyPlaceholder="newContainer.environment.keyPlaceholder"
|
||||
valueLabel="newContainer.environment.valueLabel"
|
||||
valuePlaceholder="newContainer.environment.valuePlaceholder"
|
||||
}}
|
||||
<span class="m-0 block">{{t 'newCatalog.helm.label'}}</span>
|
||||
<span class="help-block">{{t 'newCatalog.helm.protip'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
<div class="accordion-content row">
|
||||
{{#if selectedTemplateModel}}
|
||||
{{#if (eq templateKind 'native')}}
|
||||
{{input-answers
|
||||
selectedTemplate=selectedTemplateModel
|
||||
showHeader=false
|
||||
}}
|
||||
{{else}}
|
||||
<div class="span-12">
|
||||
{{#if selectedTemplateModel.questions}}
|
||||
{{input-answers
|
||||
selectedTemplate=selectedTemplateModel
|
||||
showHeader=false
|
||||
}}
|
||||
{{else}}
|
||||
{{form-key-value
|
||||
initialMap=catalogApp.answers
|
||||
changed=(action (mut catalogApp.answers))
|
||||
allowEmptyValue=false
|
||||
editing=true
|
||||
header=(t 'newCatalog.answers.label')
|
||||
addActionLabel="newCatalog.answers.addAction"
|
||||
keyLabel="newContainer.environment.keyLabel"
|
||||
keyPlaceholder="newContainer.environment.keyPlaceholder"
|
||||
valueLabel="newContainer.environment.valueLabel"
|
||||
valuePlaceholder="newContainer.environment.valuePlaceholder"
|
||||
}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and selectedTemplateModel (not getTemplate.isRunning))}}
|
||||
{{#if showPreview}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{{#if hasBlock}}
|
||||
{{ yield this}}
|
||||
{{ else }}
|
||||
{{yield this}}
|
||||
{{else}}
|
||||
{{#if currentVersion}}
|
||||
{{#tooltip-element type="tooltip-basic" model=currentVersion tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="upgrade"}}
|
||||
{{t (concat 'upgradeBtn.status.' upgradeStatus)}}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export default Mixin.create({
|
|||
color: computed('upgradeStatus', function() {
|
||||
switch ( get(this, 'upgradeStatus') ) {
|
||||
case NONE:
|
||||
return 'hide';
|
||||
return 'none';
|
||||
case CURRENT:
|
||||
case LOADING:
|
||||
return 'bg-default';
|
||||
|
|
@ -98,10 +98,11 @@ export default Mixin.create({
|
|||
},
|
||||
|
||||
updateStatus() {
|
||||
let state = get(this, 'model.state');
|
||||
let info = get(this, 'model.externalIdInfo');
|
||||
let state = get(this, 'model.state');
|
||||
let info = get(this, 'model.externalIdInfo');
|
||||
let catalogTemplate = get(this, 'model.catalogTemplate');
|
||||
let upgradeVersions={};
|
||||
let upgradeVersions = {};
|
||||
let allVersions = {};
|
||||
|
||||
if ( state === 'upgraded' ) {
|
||||
set(this, 'upgradeStatus', UPGRADED);
|
||||
|
|
@ -119,7 +120,14 @@ export default Mixin.create({
|
|||
set(this, 'upgradeStatus', NONE);
|
||||
}
|
||||
|
||||
upgradeVersions = parseUpgradeVersions(catalogTemplate.get('versionLinks'), info.version, get(this, 'model'));
|
||||
if ( catalogTemplate ) {
|
||||
upgradeVersions = parseUpgradeVersions(
|
||||
get(catalogTemplate, 'versionLinks'),
|
||||
get(info, 'version'),
|
||||
get(this, 'model')
|
||||
);
|
||||
get(catalogTemplate, 'versionLinks');
|
||||
}
|
||||
|
||||
if (Object.keys(upgradeVersions).length >= 1) {
|
||||
setProperties(this, {
|
||||
|
|
@ -127,7 +135,10 @@ export default Mixin.create({
|
|||
latestVersion: Object.keys(upgradeVersions)[Object.keys(upgradeVersions).length-1],
|
||||
});
|
||||
} else {
|
||||
set(this, 'upgradeStatus', NONE);
|
||||
setProperties(this, {
|
||||
upgradeStatus: CURRENT,
|
||||
latestVersion: get(info, 'version'),
|
||||
});
|
||||
}
|
||||
|
||||
// console.log('upgradeVersions', upgradeVersions);
|
||||
|
|
@ -149,7 +160,7 @@ export default Mixin.create({
|
|||
}
|
||||
|
||||
setProperties(this, {
|
||||
allVersions: catalogTemplate.get('versionLinks'),
|
||||
allVersions: allVersions,
|
||||
upgradeVersions: upgradeVersions
|
||||
});
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -188,18 +188,20 @@ var C = {
|
|||
},
|
||||
|
||||
PROJECT: {
|
||||
TYPE_RANCHER: 'local',
|
||||
TYPE_AZURE_USER: 'azuread_user',
|
||||
TYPE_AZURE_GROUP: 'azuread_group',
|
||||
TYPE_GITHUB_USER: 'github_user',
|
||||
TYPE_GITHUB_TEAM: 'github_team',
|
||||
TYPE_GITHUB_ORG: 'github_org',
|
||||
TYPE_LDAP_USER: 'ldap_user',
|
||||
TYPE_LDAP_GROUP: 'ldap_group',
|
||||
TYPE_OPENLDAP_USER: 'openldap_user',
|
||||
TYPE_OPENLDAP_GROUP: 'openldap_group',
|
||||
TYPE_SHIBBOLETH_USER: 'shibboleth_user',
|
||||
TYPE_SHIBBOLETH_GROUP: 'shibboleth_group',
|
||||
TYPE_RANCHER: 'local',
|
||||
TYPE_ACTIVE_DIRECTORY_USER: 'activedirectory_user',
|
||||
TYPE_ACTIVE_DIRECTORY_GROUP: 'activedirectory_group',
|
||||
TYPE_AZURE_USER: 'azuread_user',
|
||||
TYPE_AZURE_GROUP: 'azuread_group',
|
||||
TYPE_GITHUB_USER: 'github_user',
|
||||
TYPE_GITHUB_TEAM: 'github_team',
|
||||
TYPE_GITHUB_ORG: 'github_org',
|
||||
TYPE_LDAP_USER: 'ldap_user',
|
||||
TYPE_LDAP_GROUP: 'ldap_group',
|
||||
TYPE_OPENLDAP_USER: 'openldap_user',
|
||||
TYPE_OPENLDAP_GROUP: 'openldap_group',
|
||||
TYPE_SHIBBOLETH_USER: 'shibboleth_user',
|
||||
TYPE_SHIBBOLETH_GROUP: 'shibboleth_group',
|
||||
|
||||
PERSON: 'person',
|
||||
TEAM: 'team',
|
||||
|
|
|
|||
|
|
@ -167,6 +167,32 @@ accountsPage:
|
|||
modal:
|
||||
password: Change Password
|
||||
|
||||
appDetailPage:
|
||||
header: "App: {appName}"
|
||||
output:
|
||||
title: Launch Output
|
||||
detail: TBD
|
||||
workloads:
|
||||
title: Workloads
|
||||
detail: Workloads created for this application.
|
||||
nodata: No workloads were created for this application.
|
||||
ingress:
|
||||
title: Ingress Rules
|
||||
detail: Ingress rules created for this application.
|
||||
nodata: No ingress rules were created for this application.
|
||||
services:
|
||||
title: Services
|
||||
detail: Services created with this application
|
||||
nodata: No services were created for this application.
|
||||
volumes:
|
||||
title: Volumes
|
||||
detail: Persistant Volume claims created with this application
|
||||
nodata: No volume claims were made for this application.
|
||||
secrets:
|
||||
title: Secrets
|
||||
detail: Secrets associated with this application
|
||||
nodata: This application has no secrets
|
||||
|
||||
podSecurityPoliciesPage:
|
||||
index:
|
||||
header: Pod Security Policies
|
||||
|
|
@ -311,8 +337,6 @@ authPage:
|
|||
buttonText:
|
||||
pre: Authenticate with IDP
|
||||
post: Waiting to hear back from IDP
|
||||
|
||||
|
||||
providerName:
|
||||
shibboleth: Shibboleth
|
||||
root:
|
||||
|
|
@ -323,33 +347,32 @@ authPage:
|
|||
header:
|
||||
enabled:
|
||||
label: "{github} is enabled"
|
||||
required: "{appName} is configured to allow access to authorized users and organizations."
|
||||
restricted: "{appName} is configured to allow access to project members, authorized users and organizations."
|
||||
# required: |
|
||||
# {appName} is configured to allow access to {orgs, plural,
|
||||
# =0 {no organizations}
|
||||
# =1 {# organization}
|
||||
# other {# organizations}
|
||||
# } and {users, plural,
|
||||
# =0 {no users}
|
||||
# =1 {# user}
|
||||
# other {# users}
|
||||
# }.
|
||||
# restricted: |
|
||||
# {appName} is configured to allow access to project members, {orgs, plural,
|
||||
# =0 {no organizations}
|
||||
# =1 {# organization}
|
||||
# other {# organizations}
|
||||
# } and {users, plural,
|
||||
# =0 {no users}
|
||||
# =1 {# user}
|
||||
# other {# users}
|
||||
# }.
|
||||
# unrestricted: "{appName} is configured to allow access to any {github} user."
|
||||
# required: "{appName} is configured to allow access to authorized users and organizations."
|
||||
# restricted: "{appName} is configured to allow access to project members, authorized users and organizations."
|
||||
required: |
|
||||
{appName} is configured to allow access to {orgs, plural,
|
||||
=0 {no organizations}
|
||||
=1 {# organization}
|
||||
other {# organizations}
|
||||
} and {users, plural,
|
||||
=0 {no users}
|
||||
=1 {# user}
|
||||
other {# users}
|
||||
}.
|
||||
restricted: |
|
||||
{appName} is configured to allow access to project members, {orgs, plural,
|
||||
=0 {no organizations}
|
||||
=1 {# organization}
|
||||
other {# organizations}
|
||||
} and {users, plural,
|
||||
=0 {no users}
|
||||
=1 {# user}
|
||||
other {# users}
|
||||
}.
|
||||
# unrestricted: "{appName} is configured to allow access to any {github} user."
|
||||
disabled:
|
||||
label: GitHub is not configured
|
||||
warning: "{appName} can be configured to restrict access to a set of GitHub users and organization members."
|
||||
|
||||
authenticated:
|
||||
header:
|
||||
text: Authentication
|
||||
|
|
@ -398,7 +421,6 @@ authPage:
|
|||
buttonText:
|
||||
pre: Authenticate with GitHub
|
||||
post: Waiting to hear back from GitHub
|
||||
|
||||
azuread:
|
||||
header:
|
||||
enabled: 'Azure AD Authentication is <b>enabled</b>'
|
||||
|
|
@ -439,8 +461,6 @@ authPage:
|
|||
label: Login Password
|
||||
pre: Authenticate with Azure
|
||||
post: Waiting to hear back from Azure
|
||||
|
||||
|
||||
localAuth:
|
||||
header:
|
||||
enabled: 'Local Authentication is enabled'
|
||||
|
|
@ -652,6 +672,7 @@ ingressPage:
|
|||
header: 'Ingress: {name}'
|
||||
table:
|
||||
noMatch: No ingresses match the current search.
|
||||
noData: You do not have any ingress rules yet.
|
||||
containerPage:
|
||||
header: 'Container: {name}'
|
||||
portsTab:
|
||||
|
|
@ -4162,6 +4183,7 @@ newCatalog:
|
|||
maintainer: "Maintainer:"
|
||||
newNamespace: New Namespace
|
||||
newApp: New Application
|
||||
appInfo: Application Read Me
|
||||
noConfig: This template has no configuration options
|
||||
official: Officially Certified
|
||||
preview: Preview
|
||||
|
|
@ -4945,7 +4967,7 @@ upgradeBtn:
|
|||
version:
|
||||
current: 'Current'
|
||||
status:
|
||||
none: 'None'
|
||||
none: 'Upgrade: None'
|
||||
loading: 'Checking upgrades...'
|
||||
current: 'Up to date'
|
||||
available: 'Upgrade available'
|
||||
|
|
|
|||
Loading…
Reference in New Issue