Merge pull request #1517 from vincent99/master

Secrets
This commit is contained in:
Vincent Fiduccia 2017-12-29 18:45:26 -07:00 committed by GitHub
commit 7ef3d78a1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 539 additions and 215 deletions

View File

@ -19,7 +19,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
pagingLabel="pagination.node"
extraSearchFields=extraSearchFields
headers=headers as |sortable kind node dt|}}

View File

@ -20,7 +20,6 @@
bulkActions=true
body=rows
sortBy=sortBy
fullRows=true
as |sortable kind obj dt|
}}
{{#if (eq kind "row")}}

View File

@ -36,7 +36,6 @@
sortBy=sortBy
headers=headers
body=filtered
fullRows=true
as |sortable kind key|
}}
{{#if (eq kind "row")}}

View File

@ -35,7 +35,6 @@
sortBy=sortBy
headers=headers
body=arranged
fullRows=true
as |sortable kind key|
}}
{{#if (eq kind "row")}}

View File

@ -19,7 +19,6 @@
sortBy=sortBy
headers=headers
body=model.receivers
fullRows=true
as |sortable kind row|
}}
{{#if (eq kind "row")}}

View File

@ -15,7 +15,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
groupByKey=groupTableBy
groupByRef="stack"
pagingLabel="pagination.loadBalancer"

View File

@ -18,7 +18,6 @@
sortBy=sortBy
headers=headers
body=model
fullRows=true
as |sortable kind cert|
}}
{{#if (eq kind "row")}}

View File

@ -16,7 +16,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
groupByKey=groupTableBy
groupByRef="namespace"
extraGroups=emptyNamespaces

View File

@ -15,7 +15,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
groupByKey=groupTableBy
groupByRef="namespace"
pagingLabel="pagination.dnsRecord"

View File

@ -253,7 +253,6 @@
descending=descending
headers=storageHeaders
body=nonRootVolumes
fullRows=true
as |sortable kind volume|
}}
{{#if (eq kind "row")}}

View File

@ -34,7 +34,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
pagingLabel="pagination.host"
subHeaders=containerHeaders
subSearchField="arrangedInstances"

View File

@ -11,7 +11,7 @@ export function initialize(/*application */) {
// Disable iOS auto-capitalization
TextField.reopen({
attributeBindings: ['autocapitalize'],
attributeBindings: ['autocapitalize','spellcheck','autocomplete'],
autocapitalize: 'none',
});
}

View File

@ -6,6 +6,7 @@ import { formatSi, parseSi, exponentNeeded } from 'shared/utils/parse-unit';
import C from 'ui/utils/constants';
import StateCounts from 'ui/mixins/state-counts';
import { inject as service } from "@ember/service";
import { reference } from 'ember-api-store/utils/denormalize';
var Machine = Resource.extend(StateCounts,{
@ -16,6 +17,8 @@ var Machine = Resource.extend(StateCounts,{
router: service(),
clusterStore: service(),
cluster: reference('clusterId','cluster'),
init() {
this._super(...arguments);
this.defineStateCounts('arrangedInstances', 'instanceStates', 'instanceCountSort');
@ -92,7 +95,11 @@ var Machine = Resource.extend(StateCounts,{
name = this.get('nodeName');
if ( name ) {
return name.replace(/\..*$/,'');
if ( name.match(/[a-z]/i) ) {
name = name.replace(/\..*$/,'');
}
return name;
}
name = this.get('requestedHostname');

View File

@ -1,19 +1,32 @@
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import { computed, get } from '@ember/object';
import Resource from 'ember-api-store/models/resource';
export default Resource.extend({
modalService: service('modal'),
router: service(),
state: 'active',
actions: {
edit: function() {
this.get('modalService').toggleModal('modal-edit-secret', this);
edit: function(act) {
this.get('router').transitionTo('secrets.detail.edit', this.get('id'));
},
},
keys: computed('data', function() {
return Object.keys(get(this, 'data')).sort();
}),
firstKey: alias('keys.firstObject'),
availableActions: function() {
var l = this.get('links');
var choices = [
{ label: 'action.edit', icon: 'icon icon-edit', action: 'edit', enabled: !!l.update },
{ 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 },

View File

@ -18,7 +18,6 @@
sortBy=sortBy
headers=headers
body=model
fullRows=true
as |sortable kind registry|
}}
{{#if (eq kind "row")}}

View File

@ -144,7 +144,9 @@ Router.map(function() {
this.route('secrets', {path: '/secrets', resetNamespace: true}, function() {
this.route('new', {path: '/add'});
this.route('index', {path: '/'});
this.route('detail', {path: '/:secret_id'});
this.route('detail', {path: '/:secret_id'}, function() {
this.route('edit');
});
});
});

View File

@ -0,0 +1,13 @@
import Controller from '@ember/controller';
export default Controller.extend({
actions: {
done() {
this.send('goToPrevious');
},
cancel() {
this.send('goToPrevious');
}
},
});

View File

@ -0,0 +1,16 @@
import Route from '@ember/routing/route';
import { get, set } from '@ember/object';
export default Route.extend({
model: function(params) {
const original = this.modelFor('secrets.detail');
set(this, 'originalModel', original);
return original.clone();
},
setupController(controller, model) {
this._super(...arguments);
set(controller,'originalModel', this.modelFor('secrets.detail'));
}
});

View File

@ -0,0 +1,7 @@
{{new-edit-secret
originalModel=originalModel
model=model
mode="edit"
done=(action "done")
cancel=(action "cancel")
}}

View File

@ -0,0 +1,4 @@
{{new-edit-secret
mode="view"
model=model
}}

View File

@ -0,0 +1,20 @@
import Route from '@ember/routing/route';
import { get } from '@ember/object';
export default Route.extend({
model: function(params) {
const all = this.modelFor('secrets');
let secret = all.projectSecrets.findBy('id', params.secret_id);
if ( secret ) {
return secret;
}
secret = all.namespacedSecrets.findBy('id', params.secret_id);
if ( secret ) {
return secret;
}
return get(this, 'store').find('secret', params.secret_id);
},
});

View File

@ -37,12 +37,25 @@ export default Controller.extend({
translationKey: 'generic.description',
sort: ['description','name','id'],
},
{
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,
},
],

View File

@ -4,6 +4,16 @@
</div>
<div class="right-buttons">
<div class="btn-group p-0 mr-10">
{{#tooltip-element type="tooltip-basic" model=(t 'nav.group.none') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params group="none") classNames="btn btn-sm bg-default"}}<i class="icon icon-secrets"></i>{{/link-to}}
{{/tooltip-element}}
{{#tooltip-element type="tooltip-basic" model=(t 'nav.group.namespace') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params group="namespace") classNames="btn btn-sm bg-default"}}<i class="icon icon-list-nested"></i>{{/link-to}}
{{/tooltip-element}}
</div>
{{#link-to "secrets.new" classNames="btn btn-sm bg-primary" disabled=scope.current.isKubernetes}}{{t 'secretsPage.index.linkTo'}}{{/link-to}}
</div>
</section>
@ -21,7 +31,7 @@
{{#if (eq kind "row")}}
{{secret-row model=row}}
{{else if (eq kind "group")}}
{{namespace-group model=inst.ref fullColspan=sortable.fullColspan showState=true}}
{{namespace-group model=row.ref noGroup="namespaceGroup.project" fullColspan=sortable.fullColspan}}
{{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")}}

View File

@ -1,5 +1,5 @@
{{new-edit-secret
editing=false
mode="new"
model=model
cancel=(action "cancel")
}}

View File

@ -37,7 +37,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
pagingLabel="pagination.workload"
subSearchField="instances"
extraSearchFields=extraSearchFields
@ -84,7 +83,6 @@
body=loadBalancers
bulkActions=true
classNames="grid sortable-table"
fullRows=true
pagingLabel="pagination.container"
searchText=searchText
sortBy=sortBy
@ -131,7 +129,6 @@
subHeaders=containerHeaders
subSearchField="instances"
bulkActions=true
fullRows=true
pagingLabel="pagination.container"
headers=dnsHeaders
as |sortable kind serv dt|}}
@ -165,7 +162,6 @@
body=model.volumes
bulkActions=true
classNames="grid sortable-table"
fullRows=true
isVisible=parent.expanded
pagingLabel="pagination.volume"
searchText=searchText

View File

@ -9,6 +9,7 @@
@import "app/styles/fonts/prompt";
@import "app/styles/fonts/icons";
@import "app/styles/fonts/zerowidthspace";
@import "app/styles/fonts/dots";
@import "app/styles/base/base";
@import "app/styles/base/color";
@import "app/styles/base/typography";

View File

@ -266,7 +266,10 @@ input.input-sm,
.input-group.input-sm .input-group-addon {
padding: 3px 8px;
font-size: 0.87em;
&:not(textarea) {
max-height: 32px;
}
}
.input-lg,

View File

@ -0,0 +1,12 @@
@font-face {
font-family: 'dotsfont';
font-weight: normal;
font-style: normal;
src: url(data:application/font-woff;charset=utf-8;base64,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) format('woff');
}
.conceal:not(:invalid):not(:active):not(:focus) {
font-family: 'dotsfont';
}

View File

@ -79,7 +79,6 @@
classNames="grid fixed mb-0 sortable-table"
bulkActions=false
pagingLabel="pagination.mount"
fullRows=true
rowActions=false
search=true
sortBy=sortBy

View File

@ -15,7 +15,6 @@
sortBy=sortBy
bulkActions=true
subRows=true
fullRows=true
groupByKey=groupTableBy
groupByRef="stack"
pagingLabel="pagination.volume"

View File

@ -74,7 +74,6 @@
search=false
sortBy=sortBy
bulkActions=false
fullRows=true
pagingLabel="pagination.node"
headers=projectHeaders as |sortable kind role dt|}}
{{#if (eq kind "row")}}
@ -107,7 +106,6 @@
search=false
sortBy=sortBy
bulkActions=false
fullRows=true
pagingLabel="pagination.node"
headers=clusterHeaders as |sortable kind role dt|}}
{{#if (eq kind "row")}}

View File

@ -61,7 +61,6 @@
search=false
sortBy=sortBy
bulkActions=false
fullRows=true
pagingLabel="pagination.node"
headers=headers as |sortable kind role dt|}}
{{#if (eq kind "row")}}

View File

@ -9,7 +9,6 @@
<section class="instances">
{{#sortable-table
classNames="grid sortable-table"
fullRows=true
sortBy=sortBy
headers=headers
body=model

View File

@ -59,7 +59,6 @@
search=false
sortBy=sortBy
bulkActions=false
fullRows=true
pagingLabel="pagination.node"
headers=headers as |sortable kind role dt|}}
{{#if (eq kind "row")}}

View File

@ -55,7 +55,6 @@
headers=headers
body=custom
sortBy=sortBy
fullRows=true
rightActions=true
as |sortable kind row dt|
}}

View File

@ -15,7 +15,6 @@
searchText=searchText
sortBy=sortBy
bulkActions=true
fullRows=true
pagingLabel="pagination.cluster"
headers=headers as |sortable kind inst dt|
}}

View File

@ -26,12 +26,12 @@
<div class="bubble bg-body round p-10"><img src="{{app.baseAssets}}assets/images/cluster-create.svg" class="mt-5" /></div>
</div>
<div class="col span-4 text-center option">
<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 "clusters.new.import" class="btn bg-primary"}}{{t 'clusterWelcome.select'}}{{/link-to}}
{{#link-to "clusters.new.import" class="btn bg-disabled"}}Coming Soon{{/link-to}}
</div>
</div>
<div class="bubble bg-body round p-10"><img src="{{app.baseAssets}}assets/images/cluster-import.svg" class="mt-5" /></div>

View File

@ -23,9 +23,9 @@
}}
<div class="row">
<div class="col span-6">
<div class="radio">
<label>{{radio-button selection=scope value="embedded"}} {{t 'clustersPage.addPage.rke.new.radio.embedded.label'}}</label>
<p class="text-info">{{t 'clustersPage.addPage.rke.new.radio.embedded.detail' appName=settings.appName}}</p>
<div class="radio text-muted">
<label>{{radio-button selection=scope value="embedded" disabled=true}} {{t 'clustersPage.addPage.rke.new.radio.embedded.label'}}</label>
<p class="text-info">{{t 'clustersPage.addPage.rke.new.radio.embedded.detail' appName=settings.appName}} &mdash; Coming Soon</p>
</div>
</div>
<div class="col span-6">
@ -50,7 +50,6 @@
body=filteredMachines
searchText=searchText
sortBy=sortBy
fullRows=true
suffix=true
bulkActions=false
rowActions=false

View File

@ -16,12 +16,11 @@
searchText=searchText
sortBy=sortBy
bulkActions=true
fullRows=true
pagingLabel="pagination.node"
headers=headers as |sortable kind nodes dt|}}
{{#if (eq kind "row")}}
{{node-row
view="cluster"
view="global"
model=nodes
fullColspan=sortable.fullColspan
dt=dt

View File

@ -5,7 +5,6 @@
<section class="instances">
{{#sortable-table
classNames="grid sortable-table"
fullRows=true
sortBy=sortBy
headers=headers
searchText=searchText

View File

@ -5,7 +5,6 @@
<section class="instances">
{{#sortable-table
classNames="grid sortable-table"
fullRows=true
sortBy=sortBy
headers=headers
searchText=searchText

View File

@ -7,6 +7,7 @@ export default Component.extend({
model : null,
size : 'xs',
inTooltip : false,
context : null,
resourceActions : service('resource-actions'),
@ -39,12 +40,7 @@ export default Component.extend({
this.get('resourceActions').set('tooltipActions', false);
}
this.get('resourceActions').show(this.get('model'), more, this.$(), offsets);
this.get('resourceActions').show(this.get('model'), more, this.$(), offsets, this.get('context'));
}
},
sendToModel(action) {
this.get('tooltipService').leave();
this.get('model').send(action);
},
});

View File

@ -12,7 +12,6 @@
subRow=subRow
subRows=subRows
pagingLabel=pagingLabel
fullRows=true
headers=headers as |sortable kind inst dt|}}
{{#if (eq kind "row")}}
{{pod-row model=inst dt=dt bulkActions=bulkActions showNode=showNode showActions=true showPrimaryActions=false fullColspan=sortable.fullColspan subRow=subRow}}

View File

@ -47,7 +47,6 @@
classNames="grid sortable-table"
body=linksArray
bulkActions=false
fullRows=true
pagingLabel="pagination.link"
headers=headers as |sortable kind row dt|}}
{{#if (eq kind "row")}}

View File

@ -38,15 +38,15 @@
{{#if showGroup}}
<div class="btn-group p-0 mr-10">
{{#tooltip-element type="tooltip-basic" model=(t 'nav.containers.groupNone') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#tooltip-element type="tooltip-basic" model=(t 'nav.group.none') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params group="none") classNames="btn btn-sm bg-default"}}<i class="icon icon-container"></i>{{/link-to}}
{{/tooltip-element}}
{{#tooltip-element type="tooltip-basic" model=(t 'nav.containers.groupService') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#tooltip-element type="tooltip-basic" model=(t 'nav.group.workload') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params group="workload") classNames="btn btn-sm bg-default"}}<i class="icon icon-service"></i>{{/link-to}}
{{/tooltip-element}}
{{#tooltip-element type="tooltip-basic" model=(t 'nav.containers.groupStack') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#tooltip-element type="tooltip-basic" model=(t 'nav.group.namespaceWorkload') tooltipTemplate='tooltip-static' aria-describedby="tooltip-base" tooltipFor="tooltipLink"}}
{{#link-to (query-params group="namespace") classNames="btn btn-sm bg-default"}}<i class="icon icon-list-nested"></i>{{/link-to}}
{{/tooltip-element}}
</div>

View File

@ -74,6 +74,8 @@ export default Component.extend({
allowEmptyValue: false,
addInitialEmptyRow: false,
allowMultilineValue: true,
base64Value: false,
concealValue: false,
editing: true,
ary: null,
@ -94,7 +96,10 @@ export default Component.extend({
return;
}
this.$('INPUT.key').last()[0].focus();
let elem = this.$('INPUT.key').last()[0];
if ( elem ) {
elem.focus();
}
});
},
@ -147,6 +152,12 @@ export default Component.extend({
}
if ( this.get('base64Value') ) {
ary.forEach((entry) => {
entry.value = AWS.util.base64.decode(entry.value).toString();
});
}
this.set('ary', ary);
if ( !ary.length && this.get('addInitialEmptyRow') )
{
@ -170,6 +181,10 @@ export default Component.extend({
var k = row.get('key').trim();
var v = row.get('value').trim();
if ( this.get('base64Value') ) {
v = AWS.util.base64.encode(v);
}
if ( k && (v || this.get('allowEmptyValue')) )
{
map[k] = v;

View File

@ -35,9 +35,9 @@
<td data-title="{{t valueLabel}}:">
{{#if editing}}
{{#if allowMultilineValue}}
{{textarea-autogrow class="form-control input-sm value" value=row.value placeholder=valuePlaceholder disabled=(eq row.editable false)}}
{{textarea-autogrow class=(concat "form-control input-sm value" (if concealValue " conceal")) spellcheck="false" required=true value=row.value placeholder=valuePlaceholder disabled=(eq row.editable false)}}
{{else}}
{{input class="form-control input-sm value" type="text" value=row.value placeholder=valuePlaceholder disabled=(eq row.editable false)}}
{{input class=(concat "form-control input-sm value" (if concealValue " conceal")) spellcheck="false" type="text" value=row.value placeholder=valuePlaceholder disabled=(eq row.editable false)}}
{{/if}}
{{else}}
{{row.value}}

View File

@ -1,21 +1,64 @@
import { observer } from '@ember/object';
import { get, set } from '@ember/object';
import { resolve, reject } from 'rsvp';
import Component from '@ember/component';
import NewOrEdit from 'shared/mixins/new-or-edit';
import ViewNewEdit from 'shared/mixins/view-new-edit';
import layout from './template';
export default Component.extend(NewOrEdit, {
export default Component.extend(ViewNewEdit, {
layout,
model: null,
userValue: '',
userValueChanged: observer('userValue', function() {
this.set('primaryResource.value', AWS.util.base64.encode(this.get('userValue')));
}),
titleKey: 'newSecret.title',
scope: 'project',
namespace: null,
actions: {
updateData(map) {
set(this, 'primaryResource.data', map);
},
cancel() {
this.sendAction('cancel');
},
},
doSave() {
let mode = get(this, 'mode');
let scope = get(this, 'scope');
let pr = get(this, 'primaryResource');
let ns = get(this, 'namespace');
if ( mode === 'edit' || scope === 'project' ) {
return this._super(...arguments);
}
let promise = resolve();
// Convert to a namespacedSecret and create the NS as needed
if ( ns ) {
let obj = pr.serialize();
obj.type = 'namespacedSecret';
pr = get(this,'store').createRecord(obj);
set(this,'primaryResource',pr);
if ( get(ns, 'id') ) {
set(pr, 'namespaceId', get(ns, 'id'));
} else if ( ns ) {
promise = ns.save().then((newNs) => {
set(pr, 'namespaceId', get(newNs, 'id'));
return newNs.waitForState('active');
});
} else {
return reject('No namespace specified');
}
}
let self = this;
let sup = self._super;
return promise.then(() => {
return sup.apply(self,arguments);
});
},
doneSaving() {

View File

@ -1,24 +1,72 @@
<section class="header clearfix">
<h1>{{t (if editing 'newSecret.title.edit' 'newSecret.title.add')}}</h1>
{{#if isView}}
<div class="right-buttons pull-right">
{{badge-state model=model}}
{{action-menu model=model showPrimary=false classNames="ml-10 inline-block" size="sm"}}
</div>
{{/if}}
<h1>{{title}}</h1>
</section>
<section class="horizontal-form container-fluid">
<div class="row">
{{#if isView}}
{{#if model.description}}
{{banner-message color='bg-secondary mb-0 mt-10' message=(linkify model.container.description)}}
{{/if}}
{{else}}
{{form-name-description
model=primaryResource
nameRequired=true
namePlaceholder="newSecret.name.placeholder"
descriptionPlaceholder="newSecret.description.placeholder"
}}
{{/if}}
{{#unless editing}}
<div class="col span-6">
<label class="acc-label pb-5">{{t 'newSecret.value.label'}}{{field-required}}</label>
{{textarea-autogrow class="form-control" value=userValue placeholder="newSecret.value.placeholder"}}
<div class="row">
<div class="col span-6" style="min-height: 106px;">
<label class="acc-label">{{t 'newSecret.scope.label'}}</label>
{{#if isNew}}
<div class="radio">
<label>{{radio-button selection=scope value="project"}}&nbsp;{{t 'newSecret.scope.project'}}</label>
</div>
{{/unless}}
<div class="radio">
<label>{{radio-button selection=scope value="namespace"}}&nbsp;{{t 'newSecret.scope.namespace'}}{{if (eq scope "namespace") ':'}}</label>
</div>
{{else}}
<div>
{{#if model.namespace}}
{{t 'newSecret.scope.namespace'}}: {{model.namespace.displayName}}
{{else}}
{{t 'newSecret.scope.project'}}
{{/if}}
</div>
{{/if}}
</div>
</section>
{{top-errors errors=errors}}
{{save-cancel editing=true save="save" cancel="cancel"}}
{{#if (and isNew (eq scope "namespace"))}}
<div class="col span-6 box">
{{form-namespace
namespace=namespace
errors=namespaceErrors
}}
</div>
{{/if}}
</div>
<div class="box mt-10">
<label class="acc-label">{{t 'newSecret.values.label'}}</label>
{{form-key-value
initialMap=primaryResource.data
addActionLabel="newSecret.addActionLabel"
addInitialEmptyRow=true
base64Value=true
concealValue=true
editing=notIsView
changed=(action "updateData")
}}
</div>
{{#unless isView}}
{{top-errors errors=errors}}
{{save-cancel editing=true save="save" cancel="viewEditCancel"}}
{{/unless}}

View File

@ -1,16 +1,10 @@
import { or, equal, not, alias } from '@ember/object/computed';
import { or } from '@ember/object/computed';
import { get, computed } from '@ember/object';
import Component from '@ember/component';
import layout from './template';
import { inject as service } from '@ember/service'
export const headersAll = [
{
name: 'expand',
sort: false,
searchField: null,
width: 30,
views: ['project'],
},
{
name: 'state',
sort: ['sortState','displayName'],
@ -24,6 +18,13 @@ export const headersAll = [
searchField: 'displayName',
translationKey: 'generic.name',
},
{
name: 'cluster',
sort: ['cluster.displayName','name','id'],
searchField: 'cluster.displayName',
translationKey: 'nodesPage.table.clusterName',
views: ['global'],
},
{
name: 'ip',
sort: ['displayIp','displayName'],
@ -54,21 +55,16 @@ export const headersAll = [
translationKey: 'nodesPage.table.pod',
views: ['cluster','global'],
},
{
name: 'instanceState',
sort: ['instanceCountSort:desc','displayName'],
searchField: null,
width: 140,
icon: 'icon icon-lg icon-container',
dtTranslationKey: 'nodesPage.table.instanceState',
translationKey: 'nodesPage.table.instanceStateWithIcon',
views: ['project'],
},
];
export const headersProject = headersAll.filter((x) => !x.views || x.views.includes('project'));
export const headersCluster = headersAll.filter((x) => !x.views || x.views.includes('cluster'));
export const headersGlobal = headersAll.filter((x) => !x.views || x.views.includes('global' ));
const headersMap = {
all: headersAll,
global: headersAll.filter((x) => !x.views || x.views.includes('global' )),
cluster: headersAll.filter((x) => !x.views || x.views.includes('cluster')),
};
export const headersCluster = headersMap.cluster;
export const headersGlobal = headersMap.global;
export default Component.extend({
layout,
@ -83,15 +79,9 @@ export default Component.extend({
showLabelRow: or('model.displayUserLabelStrings.length','model.requireAnyLabelStrings.length'),
isGlobal: equal('view', 'global'),
isCluster: equal('view','cluster'),
isProject: equal('view','project'),
showExpand: alias('isProject'),
linkName: alias('isProject'),
showInstanceStates: alias('isProject'),
showCpu: not('isProject'),
showPod: not('isProject'),
showCluster: computed('view', function() {
return !!headersMap[get(this,'view')].findBy('name','cluster');
}),
actions: {
toggle() {

View File

@ -3,12 +3,6 @@
{{check-box nodeId=model.id}}
</td>
{{#if showExpand}}
<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>
{{/if}}
<td data-title="{{dt.state}}" class="state">
{{badge-state model=model}}
</td>
@ -27,56 +21,33 @@
{{/each}}
</td>
{{#if showCluster}}
<td data-title="{{dt.cluster}}">
{{#if model.cluster}}
{{model.cluster.displayName}}
{{else}}
<b>{{t 'generic.none'}}</b>
{{/if}}
</td>
{{/if}}
<td data-title="{{dt.ip}}">
{{#copy-inline clipboardText=model.displayIp size="small"}}
{{format-ip model.displayIp}}
{{/copy-inline}}
</td>
{{#if showCpu}}
<td data-title="{{dt.cpu}}">
{{model.cpuUsage}}
</td>
{{/if}}
<td data-title="{{dt.memory}}">
{{model.memoryUsage}}
</td>
{{#if showPod}}
<td data-title="{{dt.pod}}">
{{model.podUsage}}
</td>
{{/if}}
{{#if showInstanceStates}}
<td data-title="{{dt.instanceState}}">
<div style="margin-top: 5px;">
{{progress-bar-multi
labelKey="state"
valueKey="count"
values=model.instanceStates.byColor
tooltipValues=model.instanceStates.byName
}}
<p class="text-muted m-0">
<small>
{{#if subMatches}}
{{#if (eq (get subMatches model.id) 0)}}
{{t 'pagination.containerNoSubset' count=model.arrangedInstances.length htmlSafe=true}}
{{else if (lt (get subMatches model.id) model.arrangedInstances.length)}}
{{t 'pagination.containerHighlightSubset' subset=(get subMatches model.id) count=model.arrangedInstances.length htmlSafe=true}}
{{else}}
<b>{{t 'pagination.container' pages=1 count=model.arrangedInstances.length}}</b>
{{/if}}
{{else}}
{{t 'pagination.container' pages=1 count=(concat model.arrangedInstances.length "")}}
{{/if}}
</small>
</p>
</div>
</td>
{{/if}}
<td data-title="{{dt.actions}}" class="actions">
{{action-menu model=model showPrimary=false}}

View File

@ -34,12 +34,12 @@
{{#if (and showNode model.node)}}
<a href="{{href-to "host" model.node.id}}">{{model.node.displayName}}</a> /
{{/if}}
{{t 'generic.createdDate' date=(date-from-now model.created)}}
{{t 'generic.createdDate' date=(date-from-now model.created) htmlSafe=true}}
</p>
</td>
{{#if scalePlaceholder}}
<td class="text-muted text-center">
<small>{{t 'stackRow.standalone'}}</small>
<small>{{t 'namespaceGroup.none'}}</small>
</td>
{{/if}}
{{#if showActions}}

View File

@ -5,7 +5,6 @@
headers=headers
body=model
sortBy=sortBy
fullRows=true
as |sortable kind p dt|
}}
{{#if (eq kind "row")}}

View File

@ -14,7 +14,6 @@
descending=descending
headers=headers
body=model
fullRows=true
as |sortable kind row|
}}
{{#if (eq kind "row")}}

View File

@ -4,7 +4,6 @@
searchText=searchText
sortBy=sortBy
bulkActions=false
fullRows=true
pagingLabel="pagination.port"
headers=headers as |sortable kind row dt|}}
{{#if (eq kind "row")}}

View File

@ -11,8 +11,18 @@
<td data-title="{{dt.description}}">
{{model.description}}
</td>
<td data-title="{{dt.namespace}}">
{{#if model.namespace}}
{{model.namespace.displayName}}
{{else}}
<span class="text-muted">{{t 'generic.all'}}</span>
{{/if}}
</td>
<td data-title="{{dt.keys}}">
{{join-array model.keys}}
</td>
<td data-title="{{dt.created}}">
{{date-from-now row.created}}
{{date-from-now model.created}}
</td>
<td data-title="{{dt.actions}} "class="actions">
{{action-menu model=model}}

View File

@ -4,7 +4,6 @@
body=logs
bulkActions=false
search=true
fullRows=true
sortBy=sortBy
pagingLabel="pagination.event"
headers=headers as |sortable kind row dt|}}

View File

@ -80,7 +80,6 @@
{{/if}}
{{#if groupByKey}}
{{! Note: Grouping requires fullRows}}
{{#if extraGroups.length}}
{{#each extraGroups as |group|}}
<tbody class="group">
@ -99,7 +98,7 @@
{{else}}
{{yield this (if arranged.length 'nomatch' 'norows')}}
{{/each}}
{{else if fullRows}}
{{else}}
<tbody>
{{#each pagedContent as |row|}}
{{yield this 'row' row dt (array-includes childFilterNodes row.id)}}
@ -107,32 +106,6 @@
{{yield this (if arranged.length 'nomatch' 'norows')}}
{{/each}}
</tbody>
{{else}}
<tbody>
{{#each pagedContent as |row|}}
<tr class="main-row">
{{#if bulkActions}}
<td data-title="{{generic.actions}}: " class="row-check">
{{check-box nodeId=row.id}}
</td>
{{/if}}
{{#if hasBlock}}
{{yield this 'row' row dt}}
{{else}}
{{#each headers as |header|}}
<td data-title={{header.displayName}} data-id={{row.id}}>{{select-property row header.name}}</td>
{{/each}}
{{/if}}
</tr>
{{#if hasBlock}}
{{yield this 'sub-row' row dt}}
{{/if}}
{{else}}
{{#if hasBlock}}
{{yield this (if arranged.length 'nomatch' 'norows')}}
{{/if}}
{{/each}}
</tbody>
{{/if}}
{{#if suffix}}

View File

@ -14,6 +14,7 @@ export default TextArea.extend(IntlPlaceholder, {
tagName: 'textarea',
classNames: ['no-resize','no-ease'],
attributeBindings: ['spellcheck'],
didInsertElement() {
run.scheduleOnce('afterRender', this, 'initHeights');

View File

@ -49,7 +49,6 @@
classNames="grid fixed mb-0 sortable-table"
bulkActions=false
pagingLabel="pagination.volumes"
fullRows=true
rowActions=false
search=false
stickyHeader=false

View File

@ -9,7 +9,7 @@
{{badge-state model=model}}
</td>
<td data-title="{{dt.name}}" class="clip">
<a href="{{href-to "workload" model.id}}">{{model.displayName}} <i class="icon icon-service"></i></a>
<a href="{{href-to "service" model.id}}">{{model.displayName}} <i class="icon icon-service"></i></a>
{{#if model.showTransitioningMessage}}
<div class="clip text-small {{model.stateColor}}">{{model.transitioningMessage}}</div>
{{else if model.displayEndpoints}}
@ -33,7 +33,7 @@
{{else}}
{{t 'pagination.pod' pages=1 count=(concat model.pods.length "")}}
{{/if}} /
{{t 'generic.createdDate' date=(date-from-now model.created)}}
{{t 'generic.createdDate' date=(date-from-now model.created) htmlSafe=true}}
</p>
</td>
{{/if}}

View File

@ -1,7 +1,10 @@
import { helper } from '@ember/component/helper';
import { htmlSafe} from '@ember/string';
export function dateFromNow(params) {
return moment(params[0]).fromNow();
let d = moment(params[0]);
let str = '<span title="' + d.format('llll') + '">' + d.fromNow() + '</span>';
return htmlSafe(str);
}
export default helper(dateFromNow);

View File

@ -116,7 +116,7 @@ export default Mixin.create({
type = get(event.data, 'type');
forceRemove = (event.name === 'resource.remove');
console.log(this.label, (forceRemove ? 'Remove' : 'Change'), type +':'+ event.data.id, clusterId, projectId);
//console.log(this.label, (forceRemove ? 'Remove' : 'Change'), type +':'+ event.data.id, clusterId, projectId);
if ( get(this, 'updateProjectStore') && projectId && projectStore.hasType(type) ) {
//console.log(' Update project store', type, event.data.id, projectId);

View File

@ -0,0 +1,49 @@
import Mixin from '@ember/object/mixin'
import NewOrEdit from './new-or-edit';
import { computed, get, set } from '@ember/object'
import { equal, or } from '@ember/object/computed'
import { inject as service } from '@ember/service';
export const VIEW = 'view';
export const NEW = 'new';
export const EDIT = 'edit';
export default Mixin.create(NewOrEdit, {
intl: service(),
titleKey: null,
inlineEdit: false,
isView: equal('mode', VIEW),
isNew: equal('mode', NEW),
isEdit: equal('mode', EDIT),
notView: or('isNew','isEdit'),
actions: {
inlineEdit() {
set(this, 'mode', EDIT);
set(this, 'inlineEdit', true);
},
viewEditCancel() {
if ( get(this, 'inlineEdit') ) {
set(this, 'inlineEdit', false);
set(this, 'mode', VIEW);
} else {
this.sendAction('cancel');
}
},
},
title: computed('mode', 'primaryResource.displayName', 'titleKey', function() {
const prefix = get(this, 'titleKey');
const mode = get(this, 'mode');
const intl = get(this, 'intl');
let name = get(this, 'originalModel.displayName')
|| get(this, 'primaryResource.displayName')
|| '';
return intl.t(prefix+'.'+mode, { name });
}),
});

View File

@ -9,6 +9,7 @@ export default Service.extend({
tooltipActions : null,
actionToggle : null,
actionMenu : null,
actionContext : null,
app: service(),
// offset is a parameter that we need to open in our api, it allows us to pass a
@ -20,7 +21,7 @@ export default Service.extend({
// mirror: true
// },
show: function(model,trigger,toggle, offset) {
show: function(model, trigger, toggle, offset, context) {
if (this.get('open') && this.get('actionMenu')) {
this.hide();
}
@ -28,14 +29,12 @@ export default Service.extend({
let $menu = this.set('actionMenu', $('#resource-actions'));
let $toggle = this.set('actionToggle', $(toggle||trigger));
if ( model === this.get('model') && this.get('open') )
{
// @@TODO@@ - 10-27-17 - need to figure out where event went
// event.preventDefault();
if ( model === this.get('model') && this.get('open') ) {
return;
}
this.set('model', model);
this.set('context', context);
$('BODY').one('click', () => {
// check to see if we've opened the menu
@ -85,7 +84,7 @@ export default Service.extend({
},
triggerAction: function(actionName) {
this.get('model').send(actionName);
this.get('model').send(actionName, this.get('context'));
},
activeActions: function() {

View File

@ -924,6 +924,7 @@ nodesPage:
header: Nodes
addNode: Add Node
table:
clusterName: Cluster
cpu: CPU
memory: RAM
disk: Disk
@ -1091,6 +1092,8 @@ secretsPage:
linkTo: Add Secret
noData: You do not have any Secrets yet
noMatch: No Secrets match the current search
table:
keys: Keys
servicePage:
header: '{type}: {name}'
@ -3649,15 +3652,20 @@ newReceiver:
newSecret:
title:
edit: Edit Secret
add: Add Secret
edit: 'Edit Secret: {name}'
view: 'Secret: {name}'
name:
placeholder: e.g. api-token
placeholder: e.g. api-key
scope:
label: Scope
project: Available to all namespaces in this project
namespace: Available to a single namespace
description:
placeholder: e.g. Secret token for the API
value:
label: Secret Value
placeholder: The secret value
placeholder: e.g. S3 key pair
values:
label: Secrets Values
addActionLabel: Add Secret Value
orchestrationWelcome:
simple:
@ -3904,7 +3912,7 @@ siteAccess:
namespaceGroup:
label: "Namespace: {name}"
none: Standalone
project: Project-Level
project: Any Namespace in Project
svgServiceContainer:
sidekicks: Sidekicks
@ -4087,10 +4095,12 @@ nav:
addBalancer: Add Balancer
addDns: Add Record
addVolume: Add Volume
groupNone: Flat Pod List
groupService: Group by Workload
groupStack: Group by Namespace/Workload
importCompose: Import from YAML
group:
none: Flat List
workload: Group by Workload
namespace: Group by Namespace
namespaceWorkload: Group by Namespace/Workload
hosts:
tab: Hosts
addHost: Add Host

95
vendor/dotsfont/OFL.txt vendored Normal file
View File

@ -0,0 +1,95 @@
https://github.com/kylewelsby/dotsfont
Copyright (c) 2016, Kyle Welsby (kyle@mekyle.com)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

BIN
vendor/dotsfont/dotsfont.woff vendored Normal file

Binary file not shown.

36
vendor/dotsfont/readme.md vendored Normal file
View File

@ -0,0 +1,36 @@
DotsFont: A font made of only dots
===
This font is to enable a work-around for `-webkit-text-security` property.
![Preview](./dotsfont.png)
Usage
---
Download the font
```css
@font-face {
font-family: 'dotsfont';
src: url('dotsfont.eot');
src: url('dotsfont.eot?#iefix') format('embedded-opentype'),
url('dotsfont.woff') format('woff'),
url('dotsfont.ttf') format('truetype'),
url('dotsfont.svg#dotsfontregular') format('svg');
}
[conceal]:not(:active):not(:focus) {
font-family: 'dotsfont';
}
```
```html
<span conceal>hide me</span>
```
License
---
Copyright (c) 2016, Kyle Welsby (kyle@mekyle.com)
This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is included in this repository (OFL.txt), and is also available with a FAQ at: http://scripts.sil.org/OFL