diff --git a/addons/core/public/app-icons/credential.svg b/addons/core/public/app-icons/credential.svg
new file mode 100644
index 000000000..fb9bc8a1d
--- /dev/null
+++ b/addons/core/public/app-icons/credential.svg
@@ -0,0 +1,4 @@
+
diff --git a/addons/core/public/app-icons/credentials.svg b/addons/core/public/app-icons/credentials.svg
new file mode 100644
index 000000000..72c15d48a
--- /dev/null
+++ b/addons/core/public/app-icons/credentials.svg
@@ -0,0 +1,9 @@
+
diff --git a/addons/rose/addon/styles/rose/components/table/_table.scss b/addons/rose/addon/styles/rose/components/table/_table.scss
index 40520adee..279deda1a 100644
--- a/addons/rose/addon/styles/rose/components/table/_table.scss
+++ b/addons/rose/addon/styles/rose/components/table/_table.scss
@@ -9,6 +9,10 @@
.rose-table-row {
border-bottom: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3);
text-align: left;
+
+ &:last-child {
+ border-bottom: 0;
+ }
}
// This styles are add to stop the input to apply extra margin (default on forms)
@@ -39,6 +43,9 @@
.rose-table-header-cell {
@include type.type(s, semibold);
+ }
+
+ .rose-table-header .rose-table-header-cell {
color: var(--ui-gray);
}
@@ -67,11 +74,27 @@
}
&.rose-table-condensed {
- .rose-table-cell {
+ .rose-table-cell,
+ .rose-table-header-cell {
@include type.type(s);
$lineHeight: math.div(36, 14);
line-height: $lineHeight;
- padding: math.div(sizing.rems(s), 2) sizing.rems(s);
+ padding: sizing.rems(xxs) + sizing.rems(xxxxs) sizing.rems(s);
+
+ &:first-child {
+ padding-left: 0;
+ }
+ }
+ .rose-table-header {
+ .rose-table-header-cell {
+ $lineHeight: math.div(16, 14);
+ line-height: $lineHeight;
+ padding: sizing.rems(xs) sizing.rems(s);
+
+ &:first-child {
+ padding-left: 0;
+ }
+ }
}
}
diff --git a/ui/desktop/app/components/card/index.hbs b/ui/desktop/app/components/card/index.hbs
new file mode 100644
index 000000000..1516a7bcf
--- /dev/null
+++ b/ui/desktop/app/components/card/index.hbs
@@ -0,0 +1,27 @@
+
+ {{#if (if (has-block 'header') true @heading)}}
+
+ {{/if}}
+
+
+ {{yield to='body'}}
+
+
+ {{#if (has-block 'footer')}}
+
+ {{/if}}
+
\ No newline at end of file
diff --git a/ui/desktop/app/styles/app.scss b/ui/desktop/app/styles/app.scss
index cc21ec36f..537e540ed 100644
--- a/ui/desktop/app/styles/app.scss
+++ b/ui/desktop/app/styles/app.scss
@@ -346,7 +346,6 @@
.rose-dialog-footer {
align-items: center;
- display: flex;
div:nth-child(1) {
display: flex;
@@ -360,35 +359,40 @@
width: 50%;
}
}
-
- // .credentials-card {
- // display: flex;
- // flex-direction: column;
- // margin-bottom: 12px;
-
- // &:last-child { margin-bottom: 0; }
-
- // .credentials-card-header {
- // display: flex;
- // flex-direction: row;
-
- // div {
- // display: flex;
- // width: 50%;
-
- // &:last-child {
- // justify-content: flex-end;
- // }
- // }
- // // border-bottom: 1px solid grey;
- // }
-
- // .credentials-card-body {
- // // background: yellow;
- // }
-
- // .credentials-card-footer {
- // // background: pink;
- // }
- // }
+}
+
+// Card component (app/componetns/card)
+.card {
+ border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3);
+ display: flex;
+ flex-direction: column;
+ margin-bottom: sizing.rems(m);
+
+ .card-header {
+ align-items: center;
+ border-bottom: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3);
+ display: flex;
+ justify-content: flex-start;
+ padding: sizing.rems(s) sizing.rems(m);
+
+ h2 {
+ @include type.type(s, normal);
+ color: var(--ui-gray-starker-1);
+ margin: 0;
+ padding: sizing.rems(xxs) + sizing.rems(xxxs) 0;
+ }
+
+ .rose-icon {
+ margin-right: sizing.rems(xxxs);
+ }
+ }
+
+ .card-body {
+ padding: sizing.rems(s);
+ }
+
+ .card-footer {
+ border-top: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3);
+ padding: sizing.rems(s);
+ }
}
diff --git a/ui/desktop/app/templates/scopes/scope/projects/targets.hbs b/ui/desktop/app/templates/scopes/scope/projects/targets.hbs
index 3fee051d6..1fa2603c6 100644
--- a/ui/desktop/app/templates/scopes/scope/projects/targets.hbs
+++ b/ui/desktop/app/templates/scopes/scope/projects/targets.hbs
@@ -20,18 +20,43 @@
<:body>
{{t 'resources.target.messages.proxy_url.title'}}
({{t 'resources.target.types.tcp'}})
-
- {{session.proxy_address}}:{{session.proxy_port}}
-
+
+
+ {{session.proxy_address}}:{{session.proxy_port}}
+
+
{{!
- Credentials
}}
+ Credentials
+
+ <:body>
+
+
+
+ Key
+ Value
+
+
+
+
+ foo
+ Value
+
+
+ ttl
+ Test
+
+
+
+
+
+ }}
<:footer>
diff --git a/ui/desktop/tests/integration/components/card-test.js b/ui/desktop/tests/integration/components/card-test.js
new file mode 100644
index 000000000..fdb37919b
--- /dev/null
+++ b/ui/desktop/tests/integration/components/card-test.js
@@ -0,0 +1,45 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | card', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ await render(hbs``);
+ assert.ok(find('.card'));
+ });
+
+ test('it renders with content', async function (assert) {
+ await render(hbs`
+
+ <:header>
+ <:body>
+ <:footer>
+
+ `);
+
+ assert.ok(find('.card'));
+ assert.ok(find('.card-header'));
+ assert.ok(find('.card-body'));
+ assert.ok(find('.card-footer'));
+ });
+
+ test('header renders an icon when defined', async function (assert) {
+ await render(hbs`
+
+ <:header>
+ <:body>
+ <:footer>
+
+ `);
+
+ assert.ok(find('.card'));
+ assert.ok(find('.card-header'));
+ assert.ok(find('.card-header .rose-icon'));
+ assert.equal(this.element.textContent.trim(), 'This is a heading test');
+ });
+});