diff --git a/app/components/file-table-item.js b/app/components/file-table-item.js
new file mode 100644
index 0000000..88d7593
--- /dev/null
+++ b/app/components/file-table-item.js
@@ -0,0 +1,7 @@
+import Component from '@ember/component';
+
+const defaultFile = {};
+
+export default Component.extend({
+ file: defaultFile,
+});
diff --git a/app/components/file-table.js b/app/components/file-table.js
new file mode 100644
index 0000000..b93ecdf
--- /dev/null
+++ b/app/components/file-table.js
@@ -0,0 +1,6 @@
+import Component from '@ember/component';
+const defaultFiles = [];
+
+export default Component.extend({
+ files: defaultFiles,
+});
diff --git a/app/templates/components/file-table-item.hbs b/app/templates/components/file-table-item.hbs
new file mode 100644
index 0000000..706bfc0
--- /dev/null
+++ b/app/templates/components/file-table-item.hbs
@@ -0,0 +1,25 @@
+
+
+
+ |
+
+ {{file.name}}
+ |
+
+ {{file.device}}
+ |
+
+ {{file.path}}
+ |
+
+
+
+
+ |
+
+ {{file.status}}
+ |
+
\ No newline at end of file
diff --git a/app/templates/components/file-table.hbs b/app/templates/components/file-table.hbs
new file mode 100644
index 0000000..06a593a
--- /dev/null
+++ b/app/templates/components/file-table.hbs
@@ -0,0 +1,21 @@
+
+
+
+
+
+ |
+ Name |
+ Device |
+ Path |
+ |
+ Status |
+
+
+ {{#each files as | file |}}
+ {{file-table-item file=file selected=selected}}
+ {{/each}}
+
+
\ No newline at end of file
diff --git a/tests/integration/components/file-table-item-test.js b/tests/integration/components/file-table-item-test.js
new file mode 100644
index 0000000..4e897ec
--- /dev/null
+++ b/tests/integration/components/file-table-item-test.js
@@ -0,0 +1,47 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+const genericFile = () => {
+ return {
+ name: 'foo.bar',
+ device: 'Baz',
+ path: '~/foo.bar',
+ status: 'available',
+ };
+};
+
+module('Integration | Component | file-table-item', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders expected elements', async function(assert) {
+ await render(hbs`{{file-table-item}}`);
+
+ assert.ok(this.element, 'Component itself');
+ assert.ok(find('[data-test-id=file-table-item-name]'), 'Name');
+ });
+
+ test('it renders row with generic data', async function(assert) {
+ this.set('file', genericFile());
+ await render(hbs`{{file-table-item file=file}}`);
+
+ assert.equal(find('[data-test-id=file-table-item-name]').textContent.trim(), this.file.name, 'Renders name as text');
+ assert.equal(find('[data-test-id=file-table-item-device]').textContent.trim(), this.file.device, 'Renders device as text');
+ assert.equal(find('[data-test-id=file-table-item-path]').textContent.trim(), this.file.path, 'Renders path as text');
+ assert.equal(find('[data-test-id=file-table-item-status]').textContent.trim(), this.file.status, 'Renders status as text');
+ });
+
+ test('it handles toggling status visible elements', async function(assert) {
+ this.set('file', genericFile());
+ this.set('file.status', 'scheduled');
+ await render(hbs`{{file-table-item file=file}}`);
+
+ assert.equal(find('[data-test-id=file-table-item-status]').textContent.trim(), 'scheduled', 'Renders correct status text');
+ assert.equal(find('[data-test-id=file-table-status-icon]').classList.contains('file-table-item-status-scheduled'), true, 'Status icon has expected class');
+
+ this.set('file', genericFile());
+ assert.equal(find('[data-test-id=file-table-item-status]').textContent.trim(), 'available', 'Renders correct status text');
+ assert.equal(find('[data-test-id=file-table-status-icon]').classList.contains('file-table-item-status-available'), true, 'Status icon has expected class');
+ });
+});
diff --git a/tests/integration/components/file-table-test.js b/tests/integration/components/file-table-test.js
new file mode 100644
index 0000000..7073896
--- /dev/null
+++ b/tests/integration/components/file-table-test.js
@@ -0,0 +1,19 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+module('Integration | Component | file-table', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders expected elements', async function(assert) {
+ await render(hbs`{{file-table}}`);
+
+ assert.ok(this.element, 'Component itself');
+ assert.ok(find('[data-test-id=file-table-action-bar]'), 'Action bar');
+ assert.ok(find('[data-test-action=file-table-select-all]'), 'Select all');
+ assert.ok(find('[data-test-action=file-table-download-selected]'), 'Download selected');
+ assert.ok(find('[data-test-id=file-table-header]'), 'Table header');
+ assert.notOk(find('[data-test-id=file-table-item]'), 'Should have no table rows without data');
+ });
+});
\ No newline at end of file