Merge pull request #1448 from westlywright/kube

clusters work
This commit is contained in:
Westly Wright 2017-11-22 17:22:13 -07:00 committed by GitHub
commit 5c37ba9cfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 764 additions and 211 deletions

View File

@ -65,6 +65,7 @@ module.exports = {
"no-useless-escape": 0,
"ember/use-ember-get-and-set": 0,
"ember/order-in-controllers": 0,
"ember/order-in-models": 0,
"ember/closure-actions": 0,
"ember/order-in-components": 0,
"ember/no-on-calls-in-components": 0,

View File

@ -2,24 +2,10 @@
<h1 class="pull-left">{{t 'clustersPage.header'}}</h1> <div class="vertical-middle"></div>
<div class="right-buttons">
<div class="btn-group p-0 mr-10">
{{#tooltip-element type="tooltip-basic" model=(t 'clustersPage.mode.list') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params mode="list") classNames="btn btn-sm bg-default"}}<i class="icon icon-list"></i>{{/link-to}}
{{/tooltip-element}}
{{#tooltip-element type="tooltip-basic" model=(t 'clustersPage.mode.grouped') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params mode="grouped") classNames="btn btn-sm bg-default"}}<i class="icon icon-boxview"></i>{{/link-to}}
{{/tooltip-element}}
</div>
{{#link-to "authenticated.clusters.new" class="btn bg-primary btn-sm icon-btn"}}
<span class="darken"><i class="icon icon-cluster"></i></span>
<span>{{t 'clustersPage.newCluster'}}</span>
{{/link-to}}
{{#link-to "authenticated.clusters.new-project" class="btn bg-primary btn-sm icon-btn" disabled=(eq model.clusters.length 0)}}
<span class="darken"><i class="icon icon-folder"></i></span>
<span>{{t 'clustersPage.newProject'}}</span>
{{/link-to}}
</div>
</section>
@ -32,36 +18,29 @@
</section>
{{/unless}}
{{#if (eq mode "grouped")}}
{{#sortable-table
classNames="grid sortable-table"
body=model.clusters
searchText=searchText
sortBy=sortBy
bulkActions=false
fullRows=true
subRows=true
pagingLabel="pagination.cluster"
headers=headers as |sortable kind inst dt|
}}
{{#if (eq kind "row")}}
{{cluster-row
model=inst
fullColspan=sortable.fullColspan
toggle=(action "toggleExpand" inst.id)
expanded=(array-includes expandedClusters inst.id)
launchOnCluster=(action "launchOnCluster")
useKubernetes=(action "useKubernetes")
dt=dt
}}
{{else if (eq kind "nomatch")}}
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'clusterRow.noClusterMatch'}}</td></tr>
{{else if (eq kind "norows")}}
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'clusterRow.noClusterData'}}</td></tr>
{{/if}}
{{/sortable-table}}
{{else}}
{{project-table model=model.projects showCluster=true}}
{{/if}}
<div class="mt-30 box">{{t 'clustersPage.subtext' appName=settings.appName htmlSafe=true}}</div>
{{#sortable-table
classNames="grid sortable-table"
body=model.clusters
searchText=searchText
sortBy=sortBy
bulkActions=false
fullRows=true
pagingLabel="pagination.cluster"
headers=headers as |sortable kind inst dt|
}}
{{#if (eq kind "row")}}
{{cluster-row
model=inst
fullColspan=sortable.fullColspan
toggle=(action "toggleExpand" inst.id)
expanded=(array-includes expandedClusters inst.id)
launchOnCluster=(action "launchOnCluster")
useKubernetes=(action "useKubernetes")
dt=dt
}}
{{else if (eq kind "nomatch")}}
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'clusterRow.noClusterMatch'}}</td></tr>
{{else if (eq kind "norows")}}
<tr><td colspan="{{sortable.fullColspan}}" class="text-center text-muted lacsso pt-20 pb-20">{{t 'clusterRow.noClusterData'}}</td></tr>
{{/if}}
{{/sortable-table}}

View File

@ -0,0 +1,46 @@
import EmberObject from '@ember/object';
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import C from 'ui/utils/constants';
export default Route.extend({
clusterStore: service('cluster-store'),
catalog: service(),
settings: service(),
model() {
// TODO - !!FORDEV!! removed for dev sake
let store = this.get('clusterStore');
let def = JSON.parse(this.get(`settings.${C.SETTING.CLUSTER_TEMPLATE}`)) || {};
def.type = 'cluster';
// def.systemStacks = (def.systemStacks||[]).map((stack) => {
// stack.type = 'stackConfiguration';
// return stack;
// });
let cluster = store.createRecord(def);
// return this.get('catalog').fetchTemplates({plusInfra: true}).then((templates) => {
// return EmberObject.create({
// cluster: cluster,
// allTemplates: templates
// });
// });
return EmberObject.create({cluster: cluster, allTemplates: []});
},
// teardownForComponentState: on('deactivate', function(){
// this.controller.setProperties({
// catalogItem: null,
// editCatalog: false,
// selectedTemplateUrl: null,
// catalogInfo: null,
// _catalogInfoCache: null,
// _prefetchInstance: null,
// catalogId: 'all',
// category: null,
// viewCatalog: false,
// newSystemStack: null,
// });
// })
});

View File

@ -0,0 +1,38 @@
<section class="header">
<h1>{{t 'clustersPage.newCluster'}}</h1>
</section>
<section>
<div class="row">
<div class="col span-4 text-center option option-primary">
<h2>{{t 'clustersPage.indexPage.rke.header'}}</h2>
<div class="box-sm">
<p>{{t 'clustersPage.indexPage.rke.desc'}}</p>
<div class="links" style="top: auto; bottom: 30px;">
{{#link-to "authenticated.clusters.new.rke" class="btn bg-primary"}}{{t 'clusterWelcome.select'}}{{/link-to}}
</div>
</div>
<div class="bubble bg-body round p-10"><img src="{{app.baseAssets}}assets/images/environment-standard.svg" class="mt-5" /></div>
</div>
<div class="col span-4 text-center option option-disabled">
<h2>{{t 'clustersPage.indexPage.cloud.header'}}</h2>
<div class="box-sm">
<p>{{t 'clustersPage.indexPage.cloud.desc'}}</p>
<div class="links" style="top: auto; bottom: 30px;">
{{#link-to "authenticated.clusters.cluster.host-templates" scope.currentCluster.id class="btn bg-primary"}}{{t 'clusterWelcome.select'}}{{/link-to}}
</div>
</div>
<div class="bubble bg-body round p-10"><img src="{{app.baseAssets}}assets/images/cluster-key.svg" class="mt-5" /></div>
</div>
<div class="col span-4 text-center option option-disabled">
<h2>{{t 'clustersPage.indexPage.import.header'}}</h2>
<div class="box-sm">
<p>{{t 'clustersPage.indexPage.import.desc'}}</p>
<div class="links" style="top: auto; bottom: 30px;">
{{#link-to "authenticated.clusters.cluster.host-templates" scope.currentCluster.id class="btn bg-primary"}}{{t 'clusterWelcome.select'}}{{/link-to}}
</div>
</div>
<div class="bubble bg-body round p-10"><img src="{{app.baseAssets}}assets/images/environment-import.svg" class="mt-5" /></div>
</div>
</div>
</section>

View File

@ -0,0 +1,105 @@
import Controller from '@ember/controller';
// import { copy } from '@ember/object/internals';
import { get, set } from '@ember/object';
import { inject as service } from '@ember/service';
import { computed,observer } from '@ember/object';
import { alias } from '@ember/object/computed';
const CONFIG_DEFAULT = {
advertisedHostname: '',
role: null,
type: 'rkeConfigHost',
user: '',
ssh: '',
};
export default Controller.extend({
modalService: service('modal'),
store: service('cluster-store'),
step: null,
loading: null,
newHost: null,
// clusterList: null,
canAdd: null,
cluster: alias('model'),
config: alias('model.rancherKubernetesEngineConfig'),
init() {
this._super(...arguments);
let newHostConfig = get(this, 'store').createRecord(CONFIG_DEFAULT);
set(newHostConfig, 'role', ['etcd']);
this.setProperties({
step: 1,
newHost: newHostConfig,
loading: false,
canAdd: false,
});
},
workerList: computed('config.hosts.@each.{role,advertisedHostname,user}', function() {
return ( get(this, 'config.hosts') || [] ).filter((host) => {
return (get(host, 'role')||[]).includes('worker');
});
}),
controlplaneList: computed('config.hosts.@each.{role,advertisedHostname,user}', function() {
return ( get(this, 'config.hosts') || [] ).filter((host) => {
return (get(host, 'role')||[]).includes('controlplane');
});
}),
clusterList: computed('config.hosts.@each.{role,advertisedHostname,user,ssh}', function() {
// unfilterd list of host
return ( get(this, 'config.hosts') || [] ).uniq();
}),
hostObserver: observer('newHost.user','newHost.advertisedHostname','newHost.ssh', function() {
let cName = get(this, 'newHost.user');
let hName = get(this, 'newHost.advertisedHostname');
let ssh = get(this, 'newHost.ssh');
(cName.length > 0) && (hName.length > 0) && (ssh.length > 0) ? set(this, 'canAdd', true) : set(this, 'canAdd', false);
}),
actions: {
save() {
},
cancel(prev) {
this.send('goToPrevious',prev);
},
addNew(type) {
// TODO - set role
let neu = CONFIG_DEFAULT;
set(neu, 'role', []);
this.get('modalService').toggleModal('modal-add-cluster', {
newHost: get(this, 'store').createRecord(neu),
list: get(this, type),
});
},
go() {
this.incrementProperty('step');
},
back() {
this.decrementProperty('step');
},
addHost() {
get(this, 'config.hosts').pushObject(get(this, 'newHost'));
set(this, 'newHost', get(this, 'store').createRecord(CONFIG_DEFAULT));
},
removeHost(host, roleToRemove) {
let roles = get(host, 'role');
let at = roles.indexOf(roleToRemove);
if (at >= 0) {
roles.removeAt(at);
if (roles.length === 0) {
get(this, 'config.hosts').removeObject(host);
}
}
},
useFor(host, role) {
// set knows nothing changed so it will not fire the computed propertiy change events
let roles = get(host, 'role').slice(); //clone the array
roles.addObject(role);
set(host, 'role', roles);
},
}
});

View File

@ -0,0 +1,21 @@
import Ember from 'ember';
import { inject as service } from '@ember/service';
import { get, set } from '@ember/object';
export default Ember.Route.extend({
store: service('cluster-store'),
model: function(/* params, transition */) {
// TODO - !!FORDEV!! get clusters
let store = get(this, 'store');
let def = {
type: 'rancherKubernetesEngineConfig',
hosts: [],
network: 'flannel',
auth: 'x509'
};
let config = store.createRecord(def);
let cluster = this.modelFor('authenticated.clusters.new.index');
set(cluster, 'rancherKubernetesEngineConfig', config);
return cluster;
}
});

View File

@ -0,0 +1,136 @@
<section class="header">
{{t 'clustersPage.addPage.rke.header' count=step}}
</section>
<section>
<div class="row">
{{#if (eq step 1)}}
<form class="form text-left">
{{partial "add-cluster"}}
<div class="row mb-20">
<button {{action 'addHost'}} class="btn bg-primary mt-10 pull-right {{not canAdd 'disabled'}}" disabled={{not canAdd}}>{{t 'generic.add'}}</button>
</div>
<hr/>
<div class="row mt-10">
{{#each config.hosts as | cluster |}}
<div class="row help-text mt-10 mb-10">{{t 'clustersPage.addPage.rke.minimums.cluster'}}</div>
<div class="col span-12 border">
<div class="col span-10 pl-5 ">
<h2 class="mt-5 mb-0">{{cluster.advertisedHostname}}</h2>
</div>
<div class="col span-2 text-right">
<button class="btn btn-sm bg-transparent" {{action 'removeHost' cluster 'etcd'}}><i class="icon icon-close mr-5"></i> {{t 'generic.remove'}}</button>
</div>
</div>
{{else}}
<div class="mt-10 mb-10">
<div class="row help-text">{{t 'clustersPage.addPage.rke.minimums.nocluster'}}</div>
</div>
{{/each}}
</div>
<div class="text-center pt-10">
{{#if loading}}
<button class="btn bg-primary btn-disabled" disabled><i class="icon icon-spinner icon-spin"></i> {{t 'generic.loading'}}</button>
{{else}}
{{#if config.hosts.length }}
<button {{action 'go'}} class="btn bg-primary {{not clusterList.length 'disabled'}}" disbaled={{not clusterList.length}}>{{t 'generic.save'}}</button>
{{else}}
<button class="btn bg-primary disabled" disabled>{{t 'generic.save'}}</button>
{{/if}}
<button {{action "cancel"}} class="btn bg-primary">{{t 'generic.cancel'}}</button>
{{/if}}
</div>
</form>
{{else if (eq step 2) }}
<form class="form text-left">
<div class="row">
{{#each controlplaneList as | cluster |}}
<div class="row help-text mt-10 mb-10">{{t 'clustersPage.addPage.rke.minimums.management'}}</div>
<div class="col span-12 border">
<div class="col span-10 pl-5 ">
<h2 class="mt-5 mb-0">{{cluster.advertisedHostname}}</h2>
</div>
<div class="col span-2 text-right">
<button class="btn btn-sm bg-transparent" {{action 'removeHost' cluster 'controlplane'}}><i class="icon icon-close mr-5"></i> {{t 'generic.remove'}}</button>
</div>
</div>
{{else}}
<div class="row help-text">{{t 'clustersPage.addPage.rke.minimums.noManagement'}}</div>
{{/each}}
</div>
<hr/>
<div class="row">
{{#if clusterList.length }}
<div class="row help-text mt-10 mb-10">{{t 'clustersPage.addPage.rke.reuse.nodes'}}</div>
{{#each clusterList as | cluster |}}
<div class="col span-12 border">
<div class="col span-10 pl-5 ">
<h2 class="mt-5 mb-0">{{cluster.advertisedHostname}}</h2>
</div>
<div class="col span-2 text-right">
<button class="btn btn-sm bg-transparent" {{action 'useFor' cluster 'controlplane'}}>{{t 'clustersPage.addPage.rke.reuse.management'}}</button>
</div>
</div>
{{/each}}
{{/if}}
</div>
<div class="text-center">
{{#if loading}}
<button class="btn bg-primary mt-10 btn-disabled" disabled><i class="icon icon-spinner icon-spin"></i> {{t 'generic.loading'}}</button>
{{else}}
<button {{action 'addNew' 'controlplaneList'}} class="btn bg-primary mt-10" >{{t 'generic.add'}}</button>
{{#if controlplaneList.length }}
<button {{action 'go'}} class="btn bg-primary mt-10" >{{t 'generic.save'}}</button>
{{else}}
<button class="btn bg-primary mt-10 disabled" disabled>{{t 'generic.save'}}</button>
{{/if}}
{{/if}}
</div>
</form>
{{else if (eq step 3) }}
<form class="form text-left">
<div class="row">
<div class="row help-text mt-10 mb-10">{{t 'clustersPage.addPage.rke.minimums.nodes'}}</div>
{{#each workerList as | cluster |}}
<div class="col span-12 border">
<div class="col span-10 pl-5 ">
<h2 class="mt-5 mb-0">{{cluster.advertisedHostname}}</h2>
</div>
<div class="col span-2 text-right">
<button class="btn btn-sm bg-transparent" {{action 'removeHost' cluster 'worker'}}> <i class="icon icon-close mr-5"></i>{{t 'generic.remove'}}</button>
</div>
</div>
{{else}}
<div class="mt-10 mb-10">
<div class="row help-text mt-10 mb-10">{{t 'clustersPage.addPage.rke.minimums.noNodes'}}</div>
</div>
{{/each}}
</div>
<hr/>
<div class="row">
{{#if clusterList.length }}
<div class="row help-text mt-10 mb-10">{{t 'clustersPage.addPage.rke.reuse.nodes'}}</div>
{{#each clusterList as | cluster |}}
<div class="col span-12 border">
<div class="col span-10 pl-5 ">
<h2 class="mt-5 mb-0">{{cluster.advertisedHostname}}</h2>
</div>
<div class="col span-2 text-right">
<button class="btn btn-sm bg-transparent" {{action 'useFor' cluster 'worker'}}> <i class="icon icon-close mr-5"></i>{{t 'clustersPage.addPage.rke.reuse.useNode'}}</button>
</div>
</div>
{{/each}}
{{/if}}
</div>
<div class="text-center">
{{#if loading}}
<button class="btn bg-primary mt-10 btn-disabled" disabled><i class="icon icon-spinner icon-spin"></i> {{t 'generic.loading'}}</button>
{{else}}
<button {{action 'addNew' 'workerList'}} class="btn bg-primary mt-10" >{{t 'generic.add'}}</button>
<button {{action 'save'}} class="btn bg-primary mt-10" >{{t 'generic.save'}}</button>
{{/if}}
</div>
</form>
{{/if}}
</div>
</section>

View File

@ -1,45 +0,0 @@
import { on } from '@ember/object/evented';
import EmberObject from '@ember/object';
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import C from 'ui/utils/constants';
export default Route.extend({
clusterStore: service('cluster-store'),
catalog: service(),
settings: service(),
model() {
let store = this.get('clusterStore');
let def = JSON.parse(this.get(`settings.${C.SETTING.CLUSTER_TEMPLATE}`)) || {};
def.type = 'cluster';
def.systemStacks = (def.systemStacks||[]).map((stack) => {
stack.type = 'stackConfiguration';
return stack;
})
let cluster = store.createRecord(def);
return this.get('catalog').fetchTemplates({plusInfra: true}).then((templates) => {
return EmberObject.create({
cluster: cluster,
allTemplates: templates
});
});
},
teardownForComponentState: on('deactivate', function(){
this.controller.setProperties({
catalogItem: null,
editCatalog: false,
selectedTemplateUrl: null,
catalogInfo: null,
_catalogInfoCache: null,
_prefetchInstance: null,
catalogId: 'all',
category: null,
viewCatalog: false,
newSystemStack: null,
});
})
});

View File

@ -1,5 +0,0 @@
{{new-edit-cluster
cancel=(action 'cancel')
model=model
editing=false
}}

View File

@ -1,4 +1,3 @@
import { hash } from 'rsvp';
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
@ -11,11 +10,12 @@ export default Route.extend({
},
model() {
const scope = this.get('scope');
return hash({
projects: scope.getAll({all: true, removeMissing: true}),
clusters: scope.getAllClusters({removeMissing: true}),
var clusterStore = this.get('clusterStore');
return clusterStore.find('cluster', null, {url: 'clusters', forceReload: true, removeMissing: true}).then(() => {
//return a live array so its updated
return {
clusters: clusterStore.all('cluster'),
};
});
},
});

View File

@ -99,7 +99,8 @@ export default Route.extend(Subscribe, {
if ( this.get('access.admin') && (!opt || opt === 'prompt') )
{
scheduleOnce('afterRender', this, function() {
this.get('modalService').toggleModal('modal-telemetry');
// TODO - !!FORDEV!! removed for dev sake
// this.get('modalService').toggleModal('modal-telemetry');
});
}
else if ( form && !this.get(`prefs.${C.PREFS.FEEDBACK}`) )

View File

@ -0,0 +1,40 @@
import Resource from 'ember-api-store/models/resource';
import PolledResource from 'ui/mixins/cattle-polled-resource';
var AzureKubernetesServiceConfig = Resource.extend(PolledResource, {
type: 'azureKubernetesServiceConfig',
reservedKeys: [],
actions: {
deactivate() {
return this.doAction('deactivate');
},
activate() {
return this.doAction('activate');
},
edit: function() {
},
},
availableActions: function() {
let a = this.get('actionLinks');
let l = this.get('links');
return [
{ label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: !!l.update },
{ divider: true },
{ label: 'action.activate', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate , bulkable: true},
{ label: 'action.deactivate', icon: 'icon icon-pause', action: 'deactivate', enabled: !!a.deactivate , bulkable: true},
{ divider: true },
{ label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!l.remove, altAction: 'delete', bulkable: true },
{ divider: true },
{ label: 'action.viewInApi', icon: 'icon icon-external-link',action: 'goToApi', enabled: true },
];
}.property('actionLinks.{activate,deactivate,restore}','links.{update,remove}'),
});
export default AzureKubernetesServiceConfig;

View File

@ -40,7 +40,7 @@ var Cluster = Resource.extend(PolledResource, {
_allProjects: null,
projects: function() {
projects: computed('_allProjects.@each.clusterName', function() {
let x = this.get('_allProjects');
if (!x) {
@ -48,9 +48,9 @@ var Cluster = Resource.extend(PolledResource, {
}
return x.filterBy('clusterName', this.get('id'));
}.property('_allProjects.@each.clusterName'),
}),
defaultProject: function() {
defaultProject: computed('projects.@each.{name,clusterOwner}', function() {
let projects = this.get('projects');
let out = projects.findBy('name','Default');
@ -64,54 +64,54 @@ var Cluster = Resource.extend(PolledResource, {
}
return out;
}.property('projects.@each.{name,clusterOwner}'),
}),
canEdit: computed('actionLinks.{activate,deactivate}','links.{update,remove}', function() {
return (this.get('links.update') && this.get('state') === 'inactive') ? true : false;
}),
systemProject: function() {
systemProject: computed('projects.@each.{clusterOwner}', function() {
return this.get('projects').findBy('clusterOwner', true);
}.property('projects.@each.{clusterOwner}'),
}),
availableActions: function() {
// let a = this.get('actionLinks');
availableActions: computed('actionLinks.{activate,deactivate}','links.{update,remove}', function() {
// let a = this.get('actionLinks');
let l = this.get('links');
var choices = [
{ label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: this.get('canEdit') },
{ divider: true },
// { label: 'action.activate', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate},
// { label: 'action.deactivate', icon: 'icon icon-pause', action: 'promptStop', enabled: !!a.deactivate, altAction: 'deactivate'},
// { divider: true },
// { label: 'action.activate', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate},
// { label: 'action.deactivate', icon: 'icon icon-pause', action: 'promptStop', enabled: !!a.deactivate, altAction: 'deactivate'},
// { divider: true },
{ label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!l.remove, altAction: 'delete' },
{ divider: true },
{ label: 'action.viewInApi', icon: 'icon icon-external-link',action: 'goToApi', enabled: true },
];
return choices;
}.property('actionLinks.{activate,deactivate}','links.{update,remove}'),
}),
// @TODO real data
numHosts: function() {
numHosts: computed(function() {
return 3+Math.round(Math.random()*2);
}.property(),
}),
numCores: function() {
numCores: computed('numHosts', function() {
return this.get('numHosts')*8;
}.property('numHosts'),
}),
numGhz: function() {
numGhz: computed('numCores', function() {
return 3.4*this.get('numCores');
}.property('numCores'),
}),
numMem: function() {
numMem: computed('numHosts', function() {
return 8*this.get('numHosts');
}.property('numHosts'),
}),
numStorage: function() {
numStorage: computed('numHosts', function() {
return 40*this.get('numHosts');
}.property('numHosts'),
}),
});
Cluster.reopenClass({

View File

@ -0,0 +1,40 @@
import Resource from 'ember-api-store/models/resource';
import PolledResource from 'ui/mixins/cattle-polled-resource';
var GoogleKubernetesEngineConfig = Resource.extend(PolledResource, {
type: 'googleKubernetesEngineConfig',
reservedKeys: [],
actions: {
deactivate() {
return this.doAction('deactivate');
},
activate() {
return this.doAction('activate');
},
edit: function() {
},
},
availableActions: function() {
let a = this.get('actionLinks');
let l = this.get('links');
return [
{ label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: !!l.update },
{ divider: true },
{ label: 'action.activate', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate , bulkable: true},
{ label: 'action.deactivate', icon: 'icon icon-pause', action: 'deactivate', enabled: !!a.deactivate , bulkable: true},
{ divider: true },
{ label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!l.remove, altAction: 'delete', bulkable: true },
{ divider: true },
{ label: 'action.viewInApi', icon: 'icon icon-external-link',action: 'goToApi', enabled: true },
];
}.property('actionLinks.{activate,deactivate,restore}','links.{update,remove}'),
});
export default GoogleKubernetesEngineConfig;

View File

@ -130,7 +130,7 @@ var Stack = Resource.extend(StateCounts, {
},
},
availableActions: function() {
availableActions: computed('actionLinks.{exportconfig}','links.{update,remove}','externalIdInfo.kind','canStartAll','canPauseAll','canStopAll', function() {
let a = this.get('actionLinks');
let l = this.get('links');
@ -156,9 +156,9 @@ var Stack = Resource.extend(StateCounts, {
];
return out;
}.property('actionLinks.{exportconfig}','links.{update,remove}','externalIdInfo.kind','canStartAll','canPauseAll','canStopAll'),
}),
canStartAll: function() {
canStartAll: computed('services.@each.state','actionLinks.startall', function() {
if ( !this.hasAction('startall') ) {
return false;
}
@ -169,9 +169,9 @@ var Stack = Resource.extend(StateCounts, {
}
return this.get('services').filterBy('actionLinks.activate').get('length') > 0;
}.property('services.@each.state','actionLinks.startall'),
}),
canPauseAll: function() {
canPauseAll: computed('services.@each.state','actionLinks.pauseall', function() {
if ( !this.hasAction('pauseall') ) {
return false;
}
@ -182,9 +182,9 @@ var Stack = Resource.extend(StateCounts, {
}
return this.get('services').filterBy('actionLinks.pause').get('length') > 0;
}.property('services.@each.state','actionLinks.pauseall'),
}),
canStopAll: function() {
canStopAll: computed('services.@each.state','actionLinks.stopall', function() {
if ( !this.hasAction('stopall') ) {
return false;
}
@ -201,13 +201,13 @@ var Stack = Resource.extend(StateCounts, {
}
return services.filterBy('actionLinks.deactivate').get('length') > 0 && containers.filterBy('actionLinks.stop').get('length');
}.property('services.@each.state','actionLinks.stopall'),
}),
canViewConfig: function() {
canViewConfig: computed('actionLinks.exportconfig', function() {
return !!this.get('actionLinks.exportconfig');
}.property('actionLinks.exportconfig'),
}),
combinedState: function() {
combinedState: computed('state', 'healthState', function() {
var stack = this.get('state');
var health = this.get('healthState');
@ -216,15 +216,15 @@ var Stack = Resource.extend(StateCounts, {
} else {
return stack;
}
}.property('state', 'healthState'),
}),
externalIdInfo: function() {
externalIdInfo: computed('externalId', function() {
return parseExternalId(this.get('externalId'));
}.property('externalId'),
}),
isDefault: function() {
isDefault: computed('name', function() {
return (this.get('name')||'').toLowerCase() === 'default';
}.property('name'),
}),
isEmpty: computed('instances.length', 'services.length', function() {
return false; // @TODO-2.0
@ -236,25 +236,57 @@ var Stack = Resource.extend(StateCounts, {
return false;
}),
isFromCatalog: function() {
isFromCatalog: computed('externalIdInfo.kind', function() {
let kind = this.get('externalIdInfo.kind');
return kind === C.EXTERNAL_ID.KIND_CATALOG || kind === C.EXTERNAL_ID.KIND_SYSTEM_CATALOG;
}.property('externalIdInfo.kind'),
}),
// This only works if the templates have already been loaded elsewhere...
catalogTemplate: function() {
catalogTemplate: computed('externalIdInfo.templateId', function() {
return this.get('catalog').getTemplateFromCache(this.get('externalIdInfo.templateId'));
}.property('externalIdInfo.templateId'),
}),
icon: function() {
icon: computed('catalogTemplate', function() {
let tpl = this.get('catalogTemplate');
if ( tpl ) {
return tpl.linkFor('icon');
}
}.property('catalogTemplate'),
}),
normalizedTags: computed('tags.[]', function() {
return normalizedTags(this.get('tags'));
grouping: computed('externalIdInfo.kind','group','system', function() {
var kind = this.get('externalIdInfo.kind');
if ( kind === C.EXTERNAL_ID.KIND_KUBERNETES || kind === C.EXTERNAL_ID.KIND_LEGACY_KUBERNETES )
{
return C.EXTERNAL_ID.KIND_KUBERNETES;
}
else if ( this.get('system') )
{
return C.EXTERNAL_ID.KIND_INFRA;
}
else
{
return C.EXTERNAL_ID.KIND_USER;
}
}),
normalizedTags: computed('group', {
get() {
return tagsToArray(this.get('group'));
},
set(key,value) {
this.set('group', (value||[]).map((x) => normalizeTag(x)).join(', '));
return value;
}
}),
tags: computed('group', {
get(){
return tagsToArray(this.get('group'), false);
},
set(key,value) {
this.set('group', (value||[]).map((x) => normalizeTag(x)).join(', '));
return value;
}
}),
hasTags(want) {

View File

@ -0,0 +1,41 @@
import { inject as service } from '@ember/service';
import Resource from 'ember-api-store/models/resource';
import PolledResource from 'ui/mixins/cattle-polled-resource';
var RancherKubernetesEngineConfig = Resource.extend(PolledResource, {
type: 'rancherKubernetesEngineConfig',
reservedKeys: [],
actions: {
deactivate() {
return this.doAction('deactivate');
},
activate() {
return this.doAction('activate');
},
edit: function() {
},
},
availableActions: function() {
let a = this.get('actionLinks');
let l = this.get('links');
return [
{ label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: !!l.update },
{ divider: true },
{ label: 'action.activate', icon: 'icon icon-play', action: 'activate', enabled: !!a.activate , bulkable: true},
{ label: 'action.deactivate', icon: 'icon icon-pause', action: 'deactivate', enabled: !!a.deactivate , bulkable: true},
{ divider: true },
{ label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!l.remove, altAction: 'delete', bulkable: true },
{ divider: true },
{ label: 'action.viewInApi', icon: 'icon icon-external-link',action: 'goToApi', enabled: true },
];
}.property('actionLinks.{activate,deactivate,restore}','links.{update,remove}'),
});
export default RancherKubernetesEngineConfig;

View File

@ -1,5 +1,7 @@
import Stack from 'ui/models/namespace';
var StackConfiguration = Stack.extend();
var StackConfiguration = Stack.extend({
type: 'stackConfiguration'
});
export default StackConfiguration;

View File

@ -40,7 +40,9 @@ Router.map(function() {
// Clusters
this.route('clusters', {path: '/clusters'}, function() {
this.route('index', {path: '/'});
this.route('new', {path: '/add'});
this.route('new', {path: '/add'}, function() {
this.route('rke');
});
this.route('new-project', {path: '/add-env'});
this.route('project', {path: '/env/:project_id'});

View File

@ -245,11 +245,12 @@
.border {
border: 1px solid $border;
background: lighten($border, 2%);
}
.border-dash {
border: dashed $border;
border: 1px dashed $border;
background: lighten($border, 2%);
}

View File

@ -7,12 +7,18 @@
background: $accent-border;
}
.box-sm {
padding: 75px 30px 30px 30px;
min-height: 370px;
position: relative;
}
.box {
padding: 75px 40px 40px 40px;
min-height: 410px;
position: relative;
}
.links {
position: absolute;
top: 300px;
@ -48,7 +54,8 @@
color: white;
}
.box {
.box,
.box-sm {
background-color: lighten($link-color, 40%);
}
}

View File

@ -0,0 +1,16 @@
<div>
<div class="row">
<div class="col span-6">
<label>{{t 'clustersPage.addPage.host.clusterName'}}{{field-required}}</label>
{{input type="text" value=newHost.user }}
</div>
<div class="col span-6">
<label>{{t 'clustersPage.addPage.host.hostName'}}{{field-required}}</label>
{{input type="text" value=newHost.advertisedHostname }}
</div>
</div>
<div class="pt-10 pb-15">
<label>{{t 'clustersPage.addPage.host.ssh'}}{{field-required}}</label>
{{textarea value=newHost.ssh classNames="form-control no-resize" rows="6"}}
</div>
</div>

View File

@ -5,7 +5,7 @@ module.exports = {
// Return custom template variables here.
return {
// options are large-modal or medium-modal
size: options.entity.options.size || 'medium-modal'
size: options.size || 'medium-modal'
};
}

View File

@ -64,6 +64,7 @@ module.exports = {
"no-useless-escape": 0,
"ember/use-ember-get-and-set": 0,
"ember/order-in-controllers": 0,
"ember/order-in-models": 0,
"ember/closure-actions": 0,
"ember/order-in-components": 0,
"ember/no-on-calls-in-components": 0,
@ -77,6 +78,6 @@ module.exports = {
"ember/use-brace-expansion": 0,
"ember/no-side-effects": 0,
"ember/no-capital-letters-in-routes": 0,
"generator-star-spacing": 0,
"generator-star-spacing": 0
}
};

View File

@ -42,18 +42,11 @@
</li>
{{/if}}
<li class="{{if (eq scope "clusters") 'active selected'}}">
{{#link-to-external "authenticated.clusters"}}
<i class="icon icon-cluster icon-fw"></i>
{{t 'nav.environment.manage'}}
{{/link-to-external}}
</li>
{{#if (and isOwner projects.current)}}
<li>{{#link-to-external "authenticated.clusters.project" projects.current.id class="clip"}}{{t 'nav.environment.edit' name=projects.current.displayName}}{{/link-to-external}}</li>
<li role="presentation" class="divider"></li>
{{/if}}
<li role="presentation" class="divider"></li>
{{#if projectIsMissing}}
<li role="presentation" class="dropdown-header">{{t 'nav.environment.selected'}}</li>

View File

@ -102,6 +102,10 @@
</a>
<ul class="dropdown-menu dropdown-menu-right" data-dropdown-id="header-user-menu">
<li class="{{if (eq scope "clusters") 'active selected'}}">
{{#link-to-external "authenticated.clusters"}}{{t 'nav.environment.manage'}}{{/link-to-external}}
</li>
{{#if accessEnabled}}
<li role="presentation" class="user-auth">
{{identity-block avatar=false identity=access.identity}}

View File

@ -5,16 +5,4 @@ export default Component.extend({
layout,
model: null,
tagName: '',
expanded: null,
actions: {
toggle() {
this.sendAction('toggle');
},
switchToProject(id) {
// @TODO bad
window.lc('authenticated').send('switchProject', id);
}
},
});

View File

@ -1,6 +1,5 @@
<tr class="main-row">
<td>
<i role="button" {{action "toggle"}} class="icon icon-play eased text-small text-muted {{if expanded 'icon-rotate-90'}}"><span class="visually-hidden">Open accordion</span></i>
</td>
<td data-title="{{dt.state}}" class="state">
{{badge-state model=model}}
@ -62,22 +61,3 @@
{{action-menu model=model}}
</td>
</tr>
<tr class="sub-row {{unless expanded 'hide'}}">
<td>{{! expand}}</td>
<td colspan="{{sub fullColspan 2}}">
{{#if expanded}}
{{project-table
model=model.projects
bulkActions=false
search=false
}}
{{/if}}
</td>
</tr>
{{#if expanded}}
<tr class="separator-row">
<td colspan="{{fullColspan}}"></td>
</tr>
{{/if}}

View File

@ -0,0 +1,18 @@
import Component from '@ember/component';
import ModalBase from 'shared/mixins/modal-base';
import layout from './template';
import { get/* , set */ } from '@ember/object';
import { alias } from '@ember/object/computed';
export default Component.extend(ModalBase, {
layout,
classNames: ['small-modal'],
newHost: alias('modalOpts.newHost'),
list: alias('modalOpts.list'),
actions: {
add() {
get(this, 'list').pushObject(get(this, 'newHost'));
this.send('cancel');
},
},
});

View File

@ -0,0 +1,10 @@
<div class="header clearfix">
<h1>{{t 'clustersPage.newCluster'}}</h1>
</div>
<div>
{{partial "add-cluster"}}
</div>
<div class="footer-actions">
<button {{action 'add'}} class="btn bg-primary">{{t 'generic.save'}}</button>
<button {{action "cancel"}} class="btn bg-primary">{{t 'modalWelcome.closeModal'}}</button>
</div>

View File

@ -33,18 +33,11 @@
</a>
<ul class="dropdown-menu cluster-menu" role="menu" data-dropdown-id="environment">
<li class="{{if (eq scope "clusters") 'active selected'}}">
{{#link-to "authenticated.clusters"}}
<i class="icon icon-cluster icon-fw"></i>
{{t 'nav.environment.manage'}}
{{/link-to}}
</li>
{{#if (and isOwner scope.current)}}
<li>{{#link-to "authenticated.clusters.project" scope.current.id class="clip"}}{{t 'nav.environment.edit' name=scope.current.displayName}}{{/link-to}}</li>
<li role="presentation" class="divider"></li>
{{/if}}
<li role="presentation" class="divider"></li>
{{#if projectIsMissing}}
<li role="presentation" class="dropdown-header">{{t 'nav.environment.selected'}}</li>

View File

@ -102,6 +102,10 @@
</a>
<ul class="dropdown-menu dropdown-menu-right" data-dropdown-id="header-user-menu">
<li class="{{if (eq scope "clusters") 'active selected'}}">
{{#link-to "authenticated.clusters"}}{{t 'nav.environment.manage'}}{{/link-to}}
</li>
{{#if isAdmin}}
<li class="">
{{#link-to "global-admin"}}{{t 'nav.admin.tab' appName=settings.appName}}{{/link-to}}

View File

@ -0,0 +1 @@
export { default } from 'shared/components/modal-add-cluster/component';

View File

@ -0,0 +1,69 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="2887.909 3543.104 127.082 130.651">
<defs>
<style>
.cls-1, .cls-2, .cls-4, .cls-5 {
fill: none;
stroke: #3498db;
stroke-linejoin: round;
}
.cls-1, .cls-2, .cls-4 {
stroke-linecap: round;
}
.cls-1 {
stroke-width: 1.08px;
}
.cls-3, .cls-6 {
fill: #3498db;
}
.cls-4, .cls-5 {
stroke-width: 0.72px;
}
.cls-6, .cls-7 {
opacity: 0.1;
}
</style>
</defs>
<g id="environment-gke-01" transform="translate(2877.509 3527.844)">
<path id="Path_6151" data-name="Path 6151" class="cls-1" d="M107.646,70.1l.121,37.192L75.421,125.948,75.3,88.757Z" transform="translate(13.724 11.482)"/>
<path id="Path_6152" data-name="Path 6152" class="cls-1" d="M87.242,129.586,19.521,90.092,19.4,52.9,87.121,92.394Z" transform="translate(1.903 7.845)"/>
<line id="Line_589" data-name="Line 589" class="cls-2" y2="36.344" transform="translate(105.257 91.759)"/>
<path id="Path_6153" data-name="Path 6153" class="cls-3" d="M102.408,76.748l.121,26.652-23.26,13.326-.121-26.652,23.26-13.326m0-.848a.728.728,0,0,0-.485.121L78.785,89.347a1.02,1.02,0,0,0-.485.848l.121,26.652a.956.956,0,0,0,.969.969.728.728,0,0,0,.485-.121l23.26-13.326a.943.943,0,0,0,.363-.848V76.869a1.061,1.061,0,0,0-1.09-.969Z" transform="translate(14.358 12.709)"/>
<path id="Path_6154" data-name="Path 6154" class="cls-3" d="M23.969,60.648l57.06,33.315.121,24.956L24.09,85.6l-.121-24.956m0-.848a.956.956,0,0,0-.969.969l.121,24.956a.915.915,0,0,0,.485.848l57.06,33.315a.84.84,0,0,0,1.211-.363c.121-.121.121-.242.121-.485V93.963a.915.915,0,0,0-.485-.848L24.454,59.921a.728.728,0,0,0-.485-.121Z" transform="translate(2.664 9.304)"/>
<path id="Path_6155" data-name="Path 6155" class="cls-4" d="M100.885,77.2l.121,24.956L79.2,114.755" transform="translate(14.549 12.984)"/>
<path id="Path_6156" data-name="Path 6156" class="cls-4" d="M67.265,85.875l-.121,23.139-2.544.606.121-25.32Z" transform="translate(11.461 14.485)"/>
<path id="Path_6157" data-name="Path 6157" class="cls-4" d="M65.086,109.958,62.3,108.383V82.7" transform="translate(10.975 14.147)"/>
<line id="Line_590" data-name="Line 590" class="cls-4" x1="5.573" y1="3.15" transform="translate(78.726 123.135)"/>
<path id="Path_6158" data-name="Path 6158" class="cls-4" d="M58.644,80.975v23.139l-2.544.606V79.4Z" transform="translate(9.664 13.449)"/>
<path id="Path_6159" data-name="Path 6159" class="cls-4" d="M56.586,105.058,53.8,103.483V77.8" transform="translate(9.177 13.111)"/>
<line id="Line_591" data-name="Line 591" class="cls-4" x1="4.846" y1="2.786" transform="translate(68.429 117.442)"/>
<line id="Line_592" data-name="Line 592" class="cls-4" x1="5.452" y1="3.15" transform="translate(57.526 111.142)"/>
<path id="Path_6160" data-name="Path 6160" class="cls-4" d="M50.044,76.1l-.121,23.018L47.5,99.72V74.4Z" transform="translate(7.845 12.392)"/>
<path id="Path_6161" data-name="Path 6161" class="cls-4" d="M48.008,100.058,45.1,98.483,45.221,72.8" transform="translate(7.338 12.053)"/>
<path id="Path_6162" data-name="Path 6162" class="cls-4" d="M41.565,71.2l-.121,23.018L38.9,94.82l.121-25.32Z" transform="translate(6.027 11.355)"/>
<path id="Path_6163" data-name="Path 6163" class="cls-4" d="M39.386,95.158,36.6,93.583,36.721,67.9" transform="translate(5.54 11.017)"/>
<line id="Line_593" data-name="Line 593" class="cls-4" x1="4.846" y1="2.786" transform="translate(47.713 105.448)"/>
<path id="Path_6164" data-name="Path 6164" class="cls-5" d="M33.044,66.2l-.121,23.018L30.5,89.82V64.5Z" transform="translate(4.25 10.298)"/>
<path id="Path_6165" data-name="Path 6165" class="cls-5" d="M30.686,89.958,27.9,88.383,28.021,62.7" transform="translate(3.701 9.918)"/>
<line id="Line_594" data-name="Line 594" class="cls-4" x1="4.846" y1="2.786" transform="translate(37.173 99.149)"/>
<line id="Line_595" data-name="Line 595" class="cls-5" x1="5.33" y1="3.029" transform="translate(26.27 92.728)"/>
<path id="Path_6166" data-name="Path 6166" class="cls-6" d="M137.482,104.646,89.145,132.631,10.4,85.142,20.94,78.6l-.121,6.421L88.66,124.393l31.74-19.02V97.014Z" transform="translate(0 13.28)"/>
<g id="Group_5947" data-name="Group 5947" class="cls-7" transform="translate(77.515 52.992)">
<path id="Path_6167" data-name="Path 6167" class="cls-3" d="M74.4,46.5,74.28,65.157,65.8,70.123V49.044" transform="translate(-65.8 -46.5)"/>
</g>
<path id="Path_6168" data-name="Path 6168" class="cls-6" d="M86.161,40.393V39.06a1.537,1.537,0,0,0-.121-.727c0-.242-.121-.485-.121-.727h0A5.247,5.247,0,0,0,85.8,37c0-.242-.121-.485-.121-.727V35.91a.445.445,0,0,0-.121-.363,1.722,1.722,0,0,0-.242-.727c0-.121-.121-.363-.121-.485v-.242c-.121-.242-.121-.485-.242-.727s-.121-.485-.242-.727V32.4c0-.121-.121-.242-.121-.485-.121-.242-.121-.485-.242-.727-.121-.121-.121-.363-.242-.485v-.242a2.047,2.047,0,0,1-.242-.606l-.363-.727V29a.119.119,0,0,0-.121-.121c-.121-.242-.242-.363-.242-.606l-.363-.727c-.121-.121-.121-.242-.242-.363a.119.119,0,0,0-.121-.121c-.121-.242-.242-.363-.363-.606-.242-.242-.363-.606-.606-.848a.119.119,0,0,0-.121-.121c-.242-.363-.606-.848-.848-1.211h0a5.13,5.13,0,0,1-.606-.848c-.121-.242-.363-.363-.485-.606h0c-.121-.242-.363-.363-.485-.606s-.363-.363-.485-.606a.119.119,0,0,0-.121-.121l-.121-.121-.363-.363L77.2,20.4a.423.423,0,0,0-.242-.121l-.121-.121c-.121-.121-.242-.121-.242-.242a2.127,2.127,0,0,0-.606-.485l-.242-.242-.121-.121c-.121,0-.121-.121-.242-.121-.242-.121-.363-.363-.606-.485a1.672,1.672,0,0,0-.485-.363h-.242c-.242-.121-.363-.242-.606-.363s-.363-.242-.606-.363a.119.119,0,0,1-.121-.121c-.121-.121-.242-.121-.485-.242s-.363-.242-.606-.242c-.121,0-.242-.121-.363-.121h-.242c-.242-.121-.363-.121-.606-.242s-.363-.121-.606-.242h-.242c-.121,0-.242-.121-.363-.121-.242,0-.363-.121-.606-.121h-.485c-.242,0-.363-.121-.606-.121H65.567c-.242,0-.485.121-.848.121H64.6c-.242.121-.485.121-.727.242h0a4.3,4.3,0,0,0-1.09.485L54.3,21.615a4.3,4.3,0,0,1,1.09-.485c.242-.121.606-.121.848-.242h.121a3.011,3.011,0,0,1,.969-.121h1.454c.363,0,.727.121,1.09.121h.121c.363.121.848.242,1.211.363h.121c.485.121.848.363,1.333.485h.121c.485.242.848.485,1.333.727a12.769,12.769,0,0,1,1.333.848h.121a8.488,8.488,0,0,1,1.211.969l.121.121a10.593,10.593,0,0,0,1.211.969l.121.121,1.09,1.09.121.121a12.063,12.063,0,0,0,1.211,1.333h0l1.09,1.454h0a12.69,12.69,0,0,0,.969,1.333c.242.242.363.606.606.848.121.242.363.485.485.727.121.121.121.242.242.363a13.214,13.214,0,0,1,.727,1.333.119.119,0,0,0,.121.121c.242.485.485,1.09.727,1.575v.121a8.412,8.412,0,0,1,.606,1.575v.121c.242.485.363,1.09.606,1.7v.121c.121.485.242,1.09.363,1.575v.121c.121.485.242,1.09.363,1.575h0c.121.485.121,1.09.242,1.575v.121c0,.485.121,1.09.121,1.575a5.9,5.9,0,0,1-.121,1.454v.121a5.152,5.152,0,0,1-.242,1.333v.121c-.121.363-.121.727-.242,1.09,0,.121,0,.121-.121.242-.121.363-.242.606-.363.969v.121a2.638,2.638,0,0,1-.606.969l-.121.121c-.121.242-.363.485-.485.727l-.242.242-.485.485-.242.242a5.128,5.128,0,0,1-.848.606l8.48-4.967c.242-.121.485-.363.848-.606l.242-.242.485-.485.242-.242a2.535,2.535,0,0,0,.485-.727l.121-.121h0a2.435,2.435,0,0,0,.485-.969h0v-.121c.121-.242.242-.363.242-.606,0-.121.121-.242.121-.363s0-.121.121-.242c0-.121,0-.121.121-.242a1.536,1.536,0,0,0,.121-.727v-.606a5.247,5.247,0,0,1,.121-.606V41.12h0A1.537,1.537,0,0,0,86.161,40.393Z" transform="translate(9.283)"/>
<g id="Group_5948" data-name="Group 5948" transform="translate(59.343 20.351)">
<path id="Path_6169" data-name="Path 6169" class="cls-1" d="M64.611,21.426C72.243,25.788,78.3,36.448,78.3,45.171c0,6.905-3.877,10.54-9.328,9.571V75.821l-12.72-7.269,3.513-2.059-3.513-6.057,3.513-2.059-3.513-6.057,3.756-2.181v-.485C54.677,44.444,50.8,36.327,50.8,29.422,50.8,20.578,56.978,17.065,64.611,21.426Zm0,12.841C66.428,35.358,68,34.51,68,32.329a7.211,7.211,0,0,0-3.392-5.815c-1.817-1.09-3.392-.242-3.392,1.938a7.389,7.389,0,0,0,3.392,5.815" transform="translate(-50.8 -19.557)"/>
</g>
<path id="Path_6170" data-name="Path 6170" class="cls-1" d="M66.647,46.344,51.14,37.5,19.4,56.035,87.121,95.65l32.346-18.657L84.213,56.4" transform="translate(1.903 4.589)"/>
<path id="Path_6171" data-name="Path 6171" class="cls-3" d="M72.8,63.782l8.844-5.573L72.8,53Z" transform="translate(13.195 7.866)"/>
<g id="Group_5949" data-name="Group 5949" transform="translate(77.515 52.992)">
<path id="Path_6172" data-name="Path 6172" class="cls-1" d="M74.4,46.5,74.28,65.157,65.8,70.123V49.044" transform="translate(-65.8 -46.5)"/>
</g>
<path id="Path_6173" data-name="Path 6173" class="cls-1" d="M86.161,40.393V39.06a1.537,1.537,0,0,0-.121-.727c0-.242-.121-.485-.121-.727h0A5.247,5.247,0,0,0,85.8,37c0-.242-.121-.485-.121-.727V35.91a.445.445,0,0,0-.121-.363,1.722,1.722,0,0,0-.242-.727c0-.121-.121-.363-.121-.485v-.242c-.121-.242-.121-.485-.242-.727s-.121-.485-.242-.727V32.4c0-.121-.121-.242-.121-.485-.121-.242-.121-.485-.242-.727-.121-.121-.121-.363-.242-.485v-.242a2.047,2.047,0,0,1-.242-.606l-.363-.727V29a.119.119,0,0,0-.121-.121c-.121-.242-.242-.363-.242-.606l-.363-.727c-.121-.121-.121-.242-.242-.363a.119.119,0,0,0-.121-.121c-.121-.242-.242-.363-.363-.606-.242-.242-.363-.606-.606-.848a.119.119,0,0,0-.121-.121c-.242-.363-.606-.848-.848-1.211h0a5.13,5.13,0,0,1-.606-.848c-.121-.242-.363-.363-.485-.606h0c-.121-.242-.363-.363-.485-.606s-.363-.363-.485-.606a.119.119,0,0,0-.121-.121l-.121-.121-.363-.363L77.2,20.4a.423.423,0,0,0-.242-.121l-.121-.121c-.121-.121-.242-.121-.242-.242a2.127,2.127,0,0,0-.606-.485l-.242-.242-.121-.121c-.121,0-.121-.121-.242-.121-.242-.121-.363-.363-.606-.485a1.672,1.672,0,0,0-.485-.363h-.242c-.242-.121-.363-.242-.606-.363s-.363-.242-.606-.363a.119.119,0,0,1-.121-.121c-.121-.121-.242-.121-.485-.242s-.363-.242-.606-.242c-.121,0-.242-.121-.363-.121h-.242c-.242-.121-.363-.121-.606-.242s-.363-.121-.606-.242h-.242c-.121,0-.242-.121-.363-.121-.242,0-.363-.121-.606-.121h-.485c-.242,0-.363-.121-.606-.121H65.567c-.242,0-.485.121-.848.121H64.6c-.242.121-.485.121-.727.242h0a4.3,4.3,0,0,0-1.09.485L54.3,21.615a4.3,4.3,0,0,1,1.09-.485c.242-.121.606-.121.848-.242h.121a3.011,3.011,0,0,1,.969-.121h1.454c.363,0,.727.121,1.09.121h.121c.363.121.848.242,1.211.363h.121c.485.121.848.363,1.333.485h.121c.485.242.848.485,1.333.727a12.769,12.769,0,0,1,1.333.848h.121a8.488,8.488,0,0,1,1.211.969l.121.121a10.593,10.593,0,0,0,1.211.969l.121.121,1.09,1.09.121.121a12.063,12.063,0,0,0,1.211,1.333h0l1.09,1.454h0a12.69,12.69,0,0,0,.969,1.333c.242.242.363.606.606.848.121.242.363.485.485.727.121.121.121.242.242.363a13.214,13.214,0,0,1,.727,1.333.119.119,0,0,0,.121.121c.242.485.485,1.09.727,1.575v.121a8.412,8.412,0,0,1,.606,1.575v.121c.242.485.363,1.09.606,1.7v.121c.121.485.242,1.09.363,1.575v.121c.121.485.242,1.09.363,1.575h0c.121.485.121,1.09.242,1.575v.121c0,.485.121,1.09.121,1.575a5.9,5.9,0,0,1-.121,1.454v.121a5.152,5.152,0,0,1-.242,1.333v.121c-.121.363-.121.727-.242,1.09,0,.121,0,.121-.121.242-.121.363-.242.606-.363.969v.121a2.638,2.638,0,0,1-.606.969l-.121.121c-.121.242-.363.485-.485.727l-.242.242-.485.485-.242.242a5.128,5.128,0,0,1-.848.606l8.48-4.967c.242-.121.485-.363.848-.606l.242-.242.485-.485.242-.242a2.535,2.535,0,0,0,.485-.727l.121-.121h0a2.435,2.435,0,0,0,.485-.969h0v-.121c.121-.242.242-.363.242-.606,0-.121.121-.242.121-.363s0-.121.121-.242c0-.121,0-.121.121-.242a1.536,1.536,0,0,0,.121-.727v-.606a5.247,5.247,0,0,1,.121-.606V41.12h0A1.537,1.537,0,0,0,86.161,40.393Z" transform="translate(9.283)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -7,6 +7,7 @@ languageContribute: "Help Translate Rancher"
generic:
actions: Actions
activate: Activate
add: Add
all: All
any: Any
as: as
@ -457,15 +458,10 @@ certificatesPage:
placeholder: e.g. EV cert for mydomain.com
clustersPage:
header: Clusters & Environments
header: Clusters
newCluster: Add Cluster
newProject: Add Environment
import: Import External
newHost: Add Host
alert: There are no active environments. You will need to create or activate one before you can do anything else.
mode:
list: Environment List
grouped: Grouped by Cluster
subtext: |
<h4>{appName} supports grouping resources into multiple <b class="text-info">clusters</b> and <b class="text-info">environments</b>.</h4>
<div class="row">
@ -488,6 +484,44 @@ clustersPage:
label: RAM
storage:
label: Disk
indexPage:
rke:
header: Create a RKE Cluster
desc: Rancher automatically deploys and manages Kubernetes.
cloud:
header: Create a Cloud Cluster
desc: Create and use a new cluster with in a cloud provider.
import:
header: Import Existing Cluster
desc: Deploy containers into an existing Kubernetes installation using hosts and networking it provides.
addPage:
host:
clusterName: User
hostName: Host Name
ssh: SSH Key
rke:
header: |
{count, plural,
=1 {Add RKE: Step # set up your ETCD hosts.}
=2 {Add RKE: Step # Add Managment hosts.}
=3 {Add RKE: Step # Add Nodes Hosts.}
}
reuse:
radioLabel: Specify your existing ETCD cluster
nodes: Reuse other nodes
management: Use for Managment
useNode: Use as Node
new:
radioLabel: Add new cluster
minimums:
cluster: Minimum 1 host. 3 hosts recommended.
nocluster: You have no hosts. Minimum 1 host. 3 hosts recommended.
management: Minimum 1 host. 2 hosts recommended.
noManagement: You have no management nodes. Minimum 1 host. 3 hosts recommended.
nodes: Minimum 1 host.
noNodes: You have no hosts. Minimum 1 host.
containerPage:
header: 'Container: {name}'