From 9f86b22f57dfb14e79edefcd3d05c05a910a7e4c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 13 May 2020 16:03:06 -0500 Subject: [PATCH 01/32] Add hack to allow allocation filesystem browsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There’s a lot of duplication here that’s probably worth extracting despite not meeting the three-repetitions rule because we were already simulating the API being for a task by including the task name in the URL. --- ui/app/adapters/allocation.js | 33 ++++++++++++ ui/app/components/alloc-fs-breadcrumbs.js | 42 +++++++++++++++ ui/app/components/allocation-subnav.js | 14 +++++ ui/app/components/task-file.js | 6 ++- .../allocations/allocation/fs-root.js | 3 ++ .../controllers/allocations/allocation/fs.js | 54 +++++++++++++++++++ ui/app/models/allocation.js | 8 +++ ui/app/router.js | 3 ++ .../routes/allocations/allocation/fs-root.js | 5 ++ ui/app/routes/allocations/allocation/fs.js | 42 +++++++++++++++ .../templates/allocations/allocation/fs.hbs | 49 +++++++++++++++++ .../allocations/allocation/index.hbs | 1 + .../components/alloc-fs-breadcrumbs.hbs | 14 +++++ .../components/allocation-subnav.hbs | 7 +++ .../components/fs-directory-entry.hbs | 28 +++++++--- 15 files changed, 299 insertions(+), 10 deletions(-) create mode 100644 ui/app/components/alloc-fs-breadcrumbs.js create mode 100644 ui/app/components/allocation-subnav.js create mode 100644 ui/app/controllers/allocations/allocation/fs-root.js create mode 100644 ui/app/controllers/allocations/allocation/fs.js create mode 100644 ui/app/routes/allocations/allocation/fs-root.js create mode 100644 ui/app/routes/allocations/allocation/fs.js create mode 100644 ui/app/templates/allocations/allocation/fs.hbs create mode 100644 ui/app/templates/components/alloc-fs-breadcrumbs.hbs create mode 100644 ui/app/templates/components/allocation-subnav.hbs diff --git a/ui/app/adapters/allocation.js b/ui/app/adapters/allocation.js index a2c24a5fff1..93981bc57d0 100644 --- a/ui/app/adapters/allocation.js +++ b/ui/app/adapters/allocation.js @@ -11,8 +11,41 @@ export default Watchable.extend({ data: taskName && { TaskName: taskName }, }); }, + + ls(model, path) { + return this.token + .authorizedRequest(`/v1/client/fs/ls/${model.id}?path=${encodeURIComponent(path)}`) + .then(handleFSResponse); + }, + + stat(model, path) { + return this.token + .authorizedRequest( + `/v1/client/fs/stat/${model.id}?path=${encodeURIComponent(path)}` + ) + .then(handleFSResponse); + }, }); +async function handleFSResponse(response) { + if (response.ok) { + return response.json(); + } else { + const body = await response.text(); + + // TODO update this if/when endpoint returns 404 as expected + const statusIs500 = response.status === 500; + const bodyIncludes404Text = body.includes('no such file or directory'); + + const translatedCode = statusIs500 && bodyIncludes404Text ? 404 : response.status; + + throw { + code: translatedCode, + toString: () => body, + }; + } +} + function adapterAction(path, verb = 'POST') { return function(allocation) { const url = addToPath(this.urlForFindRecord(allocation.id, 'allocation'), path); diff --git a/ui/app/components/alloc-fs-breadcrumbs.js b/ui/app/components/alloc-fs-breadcrumbs.js new file mode 100644 index 00000000000..87796df9400 --- /dev/null +++ b/ui/app/components/alloc-fs-breadcrumbs.js @@ -0,0 +1,42 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; +import { isEmpty } from '@ember/utils'; + +export default Component.extend({ + tagName: 'nav', + classNames: ['breadcrumb'], + + 'data-test-fs-breadcrumbs': true, + + allocation: null, + path: null, + + breadcrumbs: computed('path', function() { + const breadcrumbs = this.path + .split('/') + .reject(isEmpty) + .reduce((breadcrumbs, pathSegment, index) => { + let breadcrumbPath; + + if (index > 0) { + const lastBreadcrumb = breadcrumbs[index - 1]; + breadcrumbPath = `${lastBreadcrumb.path}/${pathSegment}`; + } else { + breadcrumbPath = pathSegment; + } + + breadcrumbs.push({ + name: pathSegment, + path: breadcrumbPath, + }); + + return breadcrumbs; + }, []); + + if (breadcrumbs.length) { + breadcrumbs[breadcrumbs.length - 1].isLast = true; + } + + return breadcrumbs; + }), +}); diff --git a/ui/app/components/allocation-subnav.js b/ui/app/components/allocation-subnav.js new file mode 100644 index 00000000000..133d18a27c1 --- /dev/null +++ b/ui/app/components/allocation-subnav.js @@ -0,0 +1,14 @@ +import Component from '@ember/component'; +import { inject as service } from '@ember/service'; +import { equal, or } from '@ember/object/computed'; + +export default Component.extend({ + router: service(), + + tagName: '', + + fsIsActive: equal('router.currentRouteName', 'allocations.allocation.fs'), + fsRootIsActive: equal('router.currentRouteName', 'allocations.allocation.fs-root'), + + filesLinkActive: or('fsIsActive', 'fsRootIsActive'), +}); diff --git a/ui/app/components/task-file.js b/ui/app/components/task-file.js index 03f4e52c4e0..438b8d62470 100644 --- a/ui/app/components/task-file.js +++ b/ui/app/components/task-file.js @@ -49,7 +49,8 @@ export default Component.extend({ isStreaming: false, catUrl: computed('allocation.id', 'task.name', 'file', function() { - const encodedPath = encodeURIComponent(`${this.task.name}/${this.file}`); + const taskUrlPrefix = this.task ? `${this.task.name}/` : ''; + const encodedPath = encodeURIComponent(`${taskUrlPrefix}${this.file}`); return `/v1/client/fs/cat/${this.allocation.id}?path=${encodedPath}`; }), @@ -79,7 +80,8 @@ export default Component.extend({ fileParams: computed('task.name', 'file', 'mode', function() { // The Log class handles encoding query params - const path = `${this.task.name}/${this.file}`; + const taskUrlPrefix = this.task ? `${this.task.name}/` : ''; + const path = `${taskUrlPrefix}${this.file}`; switch (this.mode) { case 'head': diff --git a/ui/app/controllers/allocations/allocation/fs-root.js b/ui/app/controllers/allocations/allocation/fs-root.js new file mode 100644 index 00000000000..2297a800ea1 --- /dev/null +++ b/ui/app/controllers/allocations/allocation/fs-root.js @@ -0,0 +1,3 @@ +import FSController from './fs'; + +export default FSController.extend(); diff --git a/ui/app/controllers/allocations/allocation/fs.js b/ui/app/controllers/allocations/allocation/fs.js new file mode 100644 index 00000000000..328c104e9fc --- /dev/null +++ b/ui/app/controllers/allocations/allocation/fs.js @@ -0,0 +1,54 @@ +import Controller from '@ember/controller'; +import { computed } from '@ember/object'; +import { filterBy } from '@ember/object/computed'; + +export default Controller.extend({ + queryParams: { + sortProperty: 'sort', + sortDescending: 'desc', + }, + + sortProperty: 'Name', + sortDescending: false, + + path: null, + allocation: null, + directoryEntries: null, + isFile: null, + stat: null, + + directories: filterBy('directoryEntries', 'IsDir'), + files: filterBy('directoryEntries', 'IsDir', false), + + pathWithLeadingSlash: computed('path', function() { + const path = this.path; + + if (path.startsWith('/')) { + return path; + } else { + return `/${path}`; + } + }), + + sortedDirectoryEntries: computed( + 'directoryEntries.[]', + 'sortProperty', + 'sortDescending', + function() { + const sortProperty = this.sortProperty; + + const directorySortProperty = sortProperty === 'Size' ? 'Name' : sortProperty; + + const sortedDirectories = this.directories.sortBy(directorySortProperty); + const sortedFiles = this.files.sortBy(sortProperty); + + const sortedDirectoryEntries = sortedDirectories.concat(sortedFiles); + + if (this.sortDescending) { + return sortedDirectoryEntries.reverse(); + } else { + return sortedDirectoryEntries; + } + } + ), +}); diff --git a/ui/app/models/allocation.js b/ui/app/models/allocation.js index 28db0e2cf45..44a8524286d 100644 --- a/ui/app/models/allocation.js +++ b/ui/app/models/allocation.js @@ -125,4 +125,12 @@ export default Model.extend({ restart(taskName) { return this.store.adapterFor('allocation').restart(this, taskName); }, + + ls(path) { + return this.store.adapterFor('allocation').ls(this, path); + }, + + stat(path) { + return this.store.adapterFor('allocation').stat(this, path); + }, }); diff --git a/ui/app/router.js b/ui/app/router.js index 2b5d1d974a3..75398f95c98 100644 --- a/ui/app/router.js +++ b/ui/app/router.js @@ -45,6 +45,9 @@ Router.map(function() { this.route('allocations', function() { this.route('allocation', { path: '/:allocation_id' }, function() { + this.route('fs-root', { path: '/fs' }); + this.route('fs', { path: '/fs/*path' }); + this.route('task', { path: '/:name' }, function() { this.route('logs'); this.route('fs-root', { path: '/fs' }); diff --git a/ui/app/routes/allocations/allocation/fs-root.js b/ui/app/routes/allocations/allocation/fs-root.js new file mode 100644 index 00000000000..eb85dc7c30b --- /dev/null +++ b/ui/app/routes/allocations/allocation/fs-root.js @@ -0,0 +1,5 @@ +import FSRoute from './fs'; + +export default FSRoute.extend({ + templateName: 'allocations/allocation/fs', +}); diff --git a/ui/app/routes/allocations/allocation/fs.js b/ui/app/routes/allocations/allocation/fs.js new file mode 100644 index 00000000000..2ccdba05850 --- /dev/null +++ b/ui/app/routes/allocations/allocation/fs.js @@ -0,0 +1,42 @@ +import Route from '@ember/routing/route'; +import RSVP from 'rsvp'; +import notifyError from 'nomad-ui/utils/notify-error'; + +export default Route.extend({ + model({ path = '/' }) { + const decodedPath = decodeURIComponent(path); + const allocation = this.modelFor('allocations.allocation'); + + if (!allocation.isRunning) { + return { + path: decodedPath, + allocation, + }; + } + + return RSVP.all([allocation.stat(path), allocation.get('node')]) + .then(([statJson]) => { + if (statJson.IsDir) { + return RSVP.hash({ + path: decodedPath, + allocation, + directoryEntries: allocation.ls(path).catch(notifyError(this)), + isFile: false, + }); + } else { + return { + path: decodedPath, + allocation, + isFile: true, + stat: statJson, + }; + } + }) + .catch(notifyError(this)); + }, + + setupController(controller, { path, allocation, directoryEntries, isFile, stat } = {}) { + this._super(...arguments); + controller.setProperties({ path, allocation, directoryEntries, isFile, stat }); + }, +}); diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs new file mode 100644 index 00000000000..ece6dbadf17 --- /dev/null +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -0,0 +1,49 @@ +{{title pathWithLeadingSlash " - Task " task.name " filesystem"}} +{{allocation-subnav allocation=allocation}} +
+ {{#if allocation.isRunning}} + {{#if isFile}} + {{#task-file allocation=allocation file=path stat=stat class="fs-explorer"}} + {{alloc-fs-breadcrumbs allocation=allocation path=path}} + {{/task-file}} + {{else}} +
+
+ {{alloc-fs-breadcrumbs allocation=allocation path=path}} +
+ {{#if directoryEntries}} + {{#list-table + source=sortedDirectoryEntries + sortProperty=sortProperty + sortDescending=sortDescending + class="boxed-section-body is-full-bleed is-compact" as |t|}} + {{#t.head}} + {{#t.sort-by prop="Name" class="is-two-thirds"}}Name{{/t.sort-by}} + {{#t.sort-by prop="Size" class="has-text-right"}}File Size{{/t.sort-by}} + {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} + {{/t.head}} + {{#t.body as |row|}} + {{fs-directory-entry path=path allocation=allocation entry=row.model}} + {{/t.body}} + {{/list-table}} + {{else}} +
+
+

No Files

+

+ Directory is currently empty. +

+
+
+ {{/if}} +
+ {{/if}} + {{else}} +
+

Task is not Running

+

+ Cannot access files of a task that is not running. +

+
+ {{/if}} +
diff --git a/ui/app/templates/allocations/allocation/index.hbs b/ui/app/templates/allocations/allocation/index.hbs index 1fcf2aa8445..10040984ac1 100644 --- a/ui/app/templates/allocations/allocation/index.hbs +++ b/ui/app/templates/allocations/allocation/index.hbs @@ -1,4 +1,5 @@ {{title "Allocation " model.name}} +{{allocation-subnav allocation=model}}
{{#if error}}
diff --git a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs new file mode 100644 index 00000000000..4e66e46a0de --- /dev/null +++ b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs @@ -0,0 +1,14 @@ +
    +
  • + {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} + / + {{/link-to}} +
  • + {{#each breadcrumbs as |breadcrumb|}} +
  • + {{#link-to "allocations.allocation.fs" allocation breadcrumb.path activeClass="is-active"}} + {{breadcrumb.name}} + {{/link-to}} +
  • + {{/each}} +
\ No newline at end of file diff --git a/ui/app/templates/components/allocation-subnav.hbs b/ui/app/templates/components/allocation-subnav.hbs new file mode 100644 index 00000000000..679f1c6e4d8 --- /dev/null +++ b/ui/app/templates/components/allocation-subnav.hbs @@ -0,0 +1,7 @@ +
+
    +
  • {{#link-to "allocations.allocation.index" allocation activeClass="is-active"}}Overview{{/link-to}}
  • + {{!--
  • {{#link-to "allocations.allocation.logs" allocation activeClass="is-active"}}Logs{{/link-to}}
  • --}} +
  • {{#link-to "allocations.allocation.fs-root" allocation class=(if filesLinkActive "is-active")}}Files{{/link-to}}
  • +
+
diff --git a/ui/app/templates/components/fs-directory-entry.hbs b/ui/app/templates/components/fs-directory-entry.hbs index cc55d30ff6f..9301dfebd95 100644 --- a/ui/app/templates/components/fs-directory-entry.hbs +++ b/ui/app/templates/components/fs-directory-entry.hbs @@ -1,14 +1,26 @@ - {{#link-to "allocations.allocation.task.fs" task.allocation task pathToEntry activeClass="is-active"}} - {{#if entry.IsDir}} - {{x-icon "folder-outline"}} - {{else}} - {{x-icon "file-outline"}} - {{/if}} + {{#if task}} + {{#link-to "allocations.allocation.task.fs" task.allocation task pathToEntry activeClass="is-active"}} + {{#if entry.IsDir}} + {{x-icon "folder-outline"}} + {{else}} + {{x-icon "file-outline"}} + {{/if}} - {{entry.Name}} - {{/link-to}} + {{entry.Name}} + {{/link-to}} + {{else}} + {{#link-to "allocations.allocation.fs" allocation pathToEntry activeClass="is-active"}} + {{#if entry.IsDir}} + {{x-icon "folder-outline"}} + {{else}} + {{x-icon "file-outline"}} + {{/if}} + + {{entry.Name}} + {{/link-to}} + {{/if}} {{#unless entry.IsDir}}{{format-bytes entry.Size}}{{/unless}} {{moment-from entry.ModTime interval=1000}} From 796883cffd373cb523d565f82170dd662d4013ba Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 13 May 2020 16:07:39 -0500 Subject: [PATCH 02/32] Fix title --- ui/app/templates/allocations/allocation/fs.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index ece6dbadf17..4d66aa5ceae 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -1,4 +1,4 @@ -{{title pathWithLeadingSlash " - Task " task.name " filesystem"}} +{{title pathWithLeadingSlash " - Allocation " allocation.shortId " filesystem"}} {{allocation-subnav allocation=allocation}}
{{#if allocation.isRunning}} From c4bf88cd763a2c2db390d997ce96fe17e368aa57 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 13 May 2020 16:08:21 -0500 Subject: [PATCH 03/32] Fix text of not-running message --- ui/app/templates/allocations/allocation/fs.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index 4d66aa5ceae..f59b453d449 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -40,9 +40,9 @@ {{/if}} {{else}}
-

Task is not Running

+

Allocation is not Running

- Cannot access files of a task that is not running. + Cannot access files of an allocation that is not running.

{{/if}} From 14f11b582ecc4c9c937e3698bd1f85a76311baa4 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 13 May 2020 16:09:46 -0500 Subject: [PATCH 04/32] Add note about allocation breadcrumb root --- ui/app/templates/components/alloc-fs-breadcrumbs.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs index 4e66e46a0de..48904030f4f 100644 --- a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs +++ b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs @@ -1,7 +1,7 @@
  • {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} - / + / {{!-- FIXME what should this be? --}} {{/link-to}}
  • {{#each breadcrumbs as |breadcrumb|}} From db0421a856573552fe32c3e559866ce8d45100bf Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 19 May 2020 10:13:10 -0500 Subject: [PATCH 05/32] Add preliminary acceptance tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a barely-different copypaste from the task fs acceptance tests… I’m not sure what’s the best way to accomplish this! --- ui/tests/acceptance/allocation-fs-test.js | 388 ++++++++++++++++++++++ ui/tests/pages/allocations/task/fs.js | 3 + 2 files changed, 391 insertions(+) create mode 100644 ui/tests/acceptance/allocation-fs-test.js diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js new file mode 100644 index 00000000000..213c8bb0cf6 --- /dev/null +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -0,0 +1,388 @@ +import { currentURL, visit } from '@ember/test-helpers'; +import { Promise } from 'rsvp'; +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; +import moment from 'moment'; + +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import Response from 'ember-cli-mirage/response'; + +import { formatBytes } from 'nomad-ui/helpers/format-bytes'; +import { filesForPath } from 'nomad-ui/mirage/config'; + +import FS from 'nomad-ui/tests/pages/allocations/task/fs'; + +let allocation; +let allocationShortId; +let files; + +const fileSort = (prop, files) => { + let dir = []; + let file = []; + files.forEach(f => { + if (f.isDir) { + dir.push(f); + } else { + file.push(f); + } + }); + + return dir.sortBy(prop).concat(file.sortBy(prop)); +}; + +module('Acceptance | allocation fs', function(hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + hooks.beforeEach(async function() { + server.create('agent'); + server.create('node', 'forceIPv4'); + const job = server.create('job', { createAllocations: false }); + + allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); + allocationShortId = allocation.id.split('-')[0]; + + // Reset files + files = []; + + // Nested files + files.push(server.create('allocFile', { isDir: true, name: 'directory' })); + files.push(server.create('allocFile', { isDir: true, name: 'another', parent: files[0] })); + files.push( + server.create('allocFile', 'file', { + name: 'something.txt', + fileType: 'txt', + parent: files[1], + }) + ); + + files.push(server.create('allocFile', { isDir: true, name: 'empty-directory' })); + files.push(server.create('allocFile', 'file', { fileType: 'txt' })); + files.push(server.create('allocFile', 'file', { fileType: 'txt' })); + }); + + test('visiting /allocations/:allocation_id/fs', async function(assert) { + await FS.visitAllocation({ id: allocation.id }); + assert.equal(currentURL(), `/allocations/${allocation.id}/fs`, 'No redirect'); + }); + + test('when the allocation is not running, an empty state is shown', async function(assert) { + // The API 500s on stat when not running + this.server.get('/client/fs/stat/:allocation_id', () => { + return new Response(500, {}, 'no such file or directory'); + }); + + allocation.update({ + clientStatus: 'complete', + }); + + await FS.visitAllocation({ id: allocation.id }); + assert.ok(FS.hasEmptyState, 'Non-running allocation has no files'); + assert.ok( + FS.emptyState.headline.includes('Allocation is not Running'), + 'Empty state explains the condition' + ); + }); + + test('visiting /allocations/:allocation_id/fs/:path', async function(assert) { + const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; + + const testPath = async filePath => { + let pathWithLeadingSlash = filePath; + + if (!pathWithLeadingSlash.startsWith('/')) { + pathWithLeadingSlash = `/${filePath}`; + } + + await FS.visitAllocationPath({ id: allocation.id, path: filePath }); + assert.equal( + currentURL(), + `/allocations/${allocation.id}/fs/${encodeURIComponent(filePath)}`, + 'No redirect' + ); + assert.equal( + document.title, + `${pathWithLeadingSlash} - Allocation ${allocationShortId} filesystem - Nomad` + ); + assert.equal(FS.breadcrumbsText, `${allocationShortId} ${filePath.replace(/\//g, ' ')}`.trim()); + }; + + await paths.reduce(async (prev, filePath) => { + await prev; + return testPath(filePath); + }, Promise.resolve()); + }); + + test('navigating allocation filesystem', async function(assert) { + await FS.visitAllocationPath({ id: allocation.id, path: '/' }); + + const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models); + + assert.ok(FS.fileViewer.isHidden); + + assert.equal(FS.directoryEntries.length, 4); + + assert.equal(FS.breadcrumbsText, allocationShortId); + + assert.equal(FS.breadcrumbs.length, 1); + assert.ok(FS.breadcrumbs[0].isActive); + assert.equal(FS.breadcrumbs[0].text, 'task-name'); + + FS.directoryEntries[0].as(directory => { + const fileRecord = sortedFiles[0]; + assert.equal(directory.name, fileRecord.name, 'directories should come first'); + assert.ok(directory.isDirectory); + assert.equal(directory.size, '', 'directory sizes are hidden'); + assert.equal(directory.lastModified, moment(fileRecord.modTime).fromNow()); + assert.notOk(directory.path.includes('//'), 'paths shouldn’t have redundant separators'); + }); + + FS.directoryEntries[2].as(file => { + const fileRecord = sortedFiles[2]; + assert.equal(file.name, fileRecord.name); + assert.ok(file.isFile); + assert.equal(file.size, formatBytes([fileRecord.size])); + assert.equal(file.lastModified, moment(fileRecord.modTime).fromNow()); + }); + + await FS.directoryEntries[0].visit(); + + assert.equal(FS.directoryEntries.length, 1); + + assert.equal(FS.breadcrumbs.length, 2); + assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`); + + assert.notOk(FS.breadcrumbs[0].isActive); + + assert.equal(FS.breadcrumbs[1].text, files[0].name); + assert.ok(FS.breadcrumbs[1].isActive); + + await FS.directoryEntries[0].visit(); + + assert.equal(FS.directoryEntries.length, 1); + assert.notOk( + FS.directoryEntries[0].path.includes('//'), + 'paths shouldn’t have redundant separators' + ); + + assert.equal(FS.breadcrumbs.length, 3); + assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name} ${files[1].name}`); + assert.equal(FS.breadcrumbs[2].text, files[1].name); + + assert.notOk( + FS.breadcrumbs[0].path.includes('//'), + 'paths shouldn’t have redundant separators' + ); + assert.notOk( + FS.breadcrumbs[1].path.includes('//'), + 'paths shouldn’t have redundant separators' + ); + + await FS.breadcrumbs[1].visit(); + assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`); + assert.equal(FS.breadcrumbs.length, 2); + }); + + test('sorting allocation filesystem directory', async function(assert) { + this.server.get('/client/fs/ls/:allocation_id', () => { + return [ + { + Name: 'aaa-big-old-file', + IsDir: false, + Size: 19190000, + ModTime: moment() + .subtract(1, 'year') + .format(), + }, + { + Name: 'mmm-small-mid-file', + IsDir: false, + Size: 1919, + ModTime: moment() + .subtract(6, 'month') + .format(), + }, + { + Name: 'zzz-med-new-file', + IsDir: false, + Size: 191900, + ModTime: moment().format(), + }, + { + Name: 'aaa-big-old-directory', + IsDir: true, + Size: 19190000, + ModTime: moment() + .subtract(1, 'year') + .format(), + }, + { + Name: 'mmm-small-mid-directory', + IsDir: true, + Size: 1919, + ModTime: moment() + .subtract(6, 'month') + .format(), + }, + { + Name: 'zzz-med-new-directory', + IsDir: true, + Size: 191900, + ModTime: moment().format(), + }, + ]; + }); + + await FS.visitAllocationPath({ id: allocation.id, path: '/' }); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'aaa-big-old-directory', + 'mmm-small-mid-directory', + 'zzz-med-new-directory', + 'aaa-big-old-file', + 'mmm-small-mid-file', + 'zzz-med-new-file', + ]); + + await FS.sortBy('Name'); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'zzz-med-new-file', + 'mmm-small-mid-file', + 'aaa-big-old-file', + 'zzz-med-new-directory', + 'mmm-small-mid-directory', + 'aaa-big-old-directory', + ]); + + await FS.sortBy('ModTime'); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'zzz-med-new-file', + 'mmm-small-mid-file', + 'aaa-big-old-file', + 'zzz-med-new-directory', + 'mmm-small-mid-directory', + 'aaa-big-old-directory', + ]); + + await FS.sortBy('ModTime'); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'aaa-big-old-directory', + 'mmm-small-mid-directory', + 'zzz-med-new-directory', + 'aaa-big-old-file', + 'mmm-small-mid-file', + 'zzz-med-new-file', + ]); + + await FS.sortBy('Size'); + + assert.deepEqual( + FS.directoryEntryNames(), + [ + 'aaa-big-old-file', + 'zzz-med-new-file', + 'mmm-small-mid-file', + 'zzz-med-new-directory', + 'mmm-small-mid-directory', + 'aaa-big-old-directory', + ], + 'expected files to be sorted by descending size and directories to be sorted by descending name' + ); + + await FS.sortBy('Size'); + + assert.deepEqual( + FS.directoryEntryNames(), + [ + 'aaa-big-old-directory', + 'mmm-small-mid-directory', + 'zzz-med-new-directory', + 'mmm-small-mid-file', + 'zzz-med-new-file', + 'aaa-big-old-file', + ], + 'expected directories to be sorted by name and files to be sorted by ascending size' + ); + }); + + test('viewing a file', async function(assert) { + const node = server.db.nodes.find(allocation.nodeId); + + server.get(`http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, function() { + return new Response(500); + }); + + await FS.visitAllocationPath({ id: allocation.id, path: '/' }); + + const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models); + const fileRecord = sortedFiles.find(f => !f.isDir); + const fileIndex = sortedFiles.indexOf(fileRecord); + + await FS.directoryEntries[fileIndex].visit(); + + assert.equal(FS.breadcrumbsText, `${task.name} ${fileRecord.name}`); + + assert.ok(FS.fileViewer.isPresent); + + const requests = this.server.pretender.handledRequests; + const secondAttempt = requests.pop(); + const firstAttempt = requests.pop(); + + assert.equal( + firstAttempt.url.split('?')[0], + `//${node.httpAddr}/v1/client/fs/readat/${allocation.id}`, + 'Client is hit first' + ); + assert.equal(firstAttempt.status, 500, 'Client request fails'); + assert.equal( + secondAttempt.url.split('?')[0], + `/v1/client/fs/readat/${allocation.id}`, + 'Server is hit second' + ); + }); + + test('viewing an empty directory', async function(assert) { + await FS.visitAllocationPath({ id: allocation.id, path: '/empty-directory' }); + + assert.ok(FS.isEmptyDirectory); + }); + + test('viewing paths that produce stat API errors', async function(assert) { + this.server.get('/client/fs/stat/:allocation_id', () => { + return new Response(500, {}, 'no such file or directory'); + }); + + await FS.visitAllocationPath({ id: allocation.id, path: '/what-is-this' }); + assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); + + await visit('/'); + + this.server.get('/client/fs/stat/:allocation_id', () => { + return new Response(999); + }); + + await FS.visitAllocationPath({ id: allocation.id, path: '/what-is-this' }); + assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); + }); + + test('viewing paths that produce ls API errors', async function(assert) { + this.server.get('/client/fs/ls/:allocation_id', () => { + return new Response(500, {}, 'no such file or directory'); + }); + + await FS.visitAllocationPath({ id: allocation.id, path: files[0].name }); + assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); + + await visit('/'); + + this.server.get('/client/fs/ls/:allocation_id', () => { + return new Response(999); + }); + + await FS.visitAllocationPath({ id: allocation.id, path: files[0].name }); + assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); + }); +}); diff --git a/ui/tests/pages/allocations/task/fs.js b/ui/tests/pages/allocations/task/fs.js index e6b6155b8cc..e2a05545e30 100644 --- a/ui/tests/pages/allocations/task/fs.js +++ b/ui/tests/pages/allocations/task/fs.js @@ -13,6 +13,9 @@ export default create({ visit: visitable('/allocations/:id/:name/fs'), visitPath: visitable('/allocations/:id/:name/fs/:path'), + visitAllocation: visitable('/allocations/:id/fs'), + visitAllocationPath: visitable('/allocations/:id/fs/:path'), + fileViewer: { scope: '[data-test-file-viewer]', }, From 4fd9f40a01def72be420de7f85b23bd64b1c29a8 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 19 May 2020 10:18:43 -0500 Subject: [PATCH 06/32] Change root marker to be allocation short id --- ui/app/templates/components/alloc-fs-breadcrumbs.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs index 48904030f4f..4f2701ebe42 100644 --- a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs +++ b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs @@ -1,7 +1,7 @@
    • {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} - / {{!-- FIXME what should this be? --}} + {{allocation.shortId}} {{/link-to}}
    • {{#each breadcrumbs as |breadcrumb|}} From 3b964c1fc7692b2cc91602a14b2cf046c290ef89 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 19 May 2020 10:28:32 -0500 Subject: [PATCH 07/32] Fix path request for empty directory --- ui/tests/acceptance/allocation-fs-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index 213c8bb0cf6..b7a744ce9b2 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -345,7 +345,7 @@ module('Acceptance | allocation fs', function(hooks) { }); test('viewing an empty directory', async function(assert) { - await FS.visitAllocationPath({ id: allocation.id, path: '/empty-directory' }); + await FS.visitAllocationPath({ id: allocation.id, path: 'empty-directory' }); assert.ok(FS.isEmptyDirectory); }); From c565940be3cab33f825e6e93b07e7f0a6de49238 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 19 May 2020 11:57:30 -0500 Subject: [PATCH 08/32] Remove stripping of leading task name in paths The assumption that we should strip the task name path prefix is no longer correct if we want to be able to browse the allocation without a task. This changes the task filesystem acceptance test files to all be nested within a task name directory, which mirrors how it works in the real setup. --- ui/mirage/config.js | 17 +++++-------- ui/tests/acceptance/task-fs-test.js | 39 +++++++++++++++++------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/ui/mirage/config.js b/ui/mirage/config.js index 367dc67bacf..a4454a49d07 100644 --- a/ui/mirage/config.js +++ b/ui/mirage/config.js @@ -393,16 +393,14 @@ export default function() { return logEncode(logFrames, logFrames.length - 1); }; - const clientAllocationFSLsHandler = function({ allocFiles }, { queryParams }) { - // Ignore the task name at the beginning of the path - const filterPath = queryParams.path.substr(queryParams.path.indexOf('/') + 1); + const clientAllocationFSLsHandler = function({ allocFiles }, { queryParams: { path } }) { + const filterPath = path.endsWith('/') ? path.substr(0, path.length - 1) : path; const files = filesForPath(allocFiles, filterPath); return this.serialize(files); }; - const clientAllocationFSStatHandler = function({ allocFiles }, { queryParams }) { - // Ignore the task name at the beginning of the path - const filterPath = queryParams.path.substr(queryParams.path.indexOf('/') + 1); + const clientAllocationFSStatHandler = function({ allocFiles }, { queryParams: { path } }) { + const filterPath = path.endsWith('/') ? path.substr(0, path.length - 1) : path; // Root path if (!filterPath) { @@ -441,15 +439,12 @@ export default function() { }; const fileOrError = function(allocFiles, path, message = 'Operation not allowed on a directory') { - // Ignore the task name at the beginning of the path - const filterPath = path.substr(path.indexOf('/') + 1); - // Root path - if (!filterPath) { + if (path === '/') { return [null, new Response(400, {}, message)]; } - const file = allocFiles.where({ path: filterPath }).models[0]; + const file = allocFiles.where({ path }).models[0]; if (file.isDir) { return [null, new Response(400, {}, message)]; } diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index cd9d0c40847..7c85adb0c54 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -14,7 +14,7 @@ import FS from 'nomad-ui/tests/pages/allocations/task/fs'; let allocation; let task; -let files; +let files, taskDirectory, directory, nestedDirectory; const fileSort = (prop, files) => { let dir = []; @@ -47,20 +47,27 @@ module('Acceptance | task fs', function(hooks) { // Reset files files = []; + taskDirectory = server.create('allocFile', { isDir: true, name: task.name }); + files.push(taskDirectory); + // Nested files - files.push(server.create('allocFile', { isDir: true, name: 'directory' })); - files.push(server.create('allocFile', { isDir: true, name: 'another', parent: files[0] })); + directory = server.create('allocFile', { isDir: true, name: 'directory', parent: taskDirectory }); + files.push(directory); + + nestedDirectory = server.create('allocFile', { isDir: true, name: 'another', parent: directory }); + files.push(nestedDirectory); + files.push( server.create('allocFile', 'file', { name: 'something.txt', fileType: 'txt', - parent: files[1], + parent: nestedDirectory, }) ); - files.push(server.create('allocFile', { isDir: true, name: 'empty-directory' })); - files.push(server.create('allocFile', 'file', { fileType: 'txt' })); - files.push(server.create('allocFile', 'file', { fileType: 'txt' })); + files.push(server.create('allocFile', { isDir: true, name: 'empty-directory', parent: taskDirectory })); + files.push(server.create('allocFile', 'file', { fileType: 'txt', parent: taskDirectory })); + files.push(server.create('allocFile', 'file', { fileType: 'txt', parent: taskDirectory })); }); test('visiting /allocations/:allocation_id/:task_name/fs', async function(assert) { @@ -118,7 +125,7 @@ module('Acceptance | task fs', function(hooks) { test('navigating allocation filesystem', async function(assert) { await FS.visitPath({ id: allocation.id, name: task.name, path: '/' }); - const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models); + const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, task.name).models); assert.ok(FS.fileViewer.isHidden); @@ -152,11 +159,11 @@ module('Acceptance | task fs', function(hooks) { assert.equal(FS.directoryEntries.length, 1); assert.equal(FS.breadcrumbs.length, 2); - assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`); + assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name}`); assert.notOk(FS.breadcrumbs[0].isActive); - assert.equal(FS.breadcrumbs[1].text, files[0].name); + assert.equal(FS.breadcrumbs[1].text, directory.name); assert.ok(FS.breadcrumbs[1].isActive); await FS.directoryEntries[0].visit(); @@ -168,8 +175,8 @@ module('Acceptance | task fs', function(hooks) { ); assert.equal(FS.breadcrumbs.length, 3); - assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name} ${files[1].name}`); - assert.equal(FS.breadcrumbs[2].text, files[1].name); + assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name} ${nestedDirectory.name}`); + assert.equal(FS.breadcrumbs[2].text, nestedDirectory.name); assert.notOk( FS.breadcrumbs[0].path.includes('//'), @@ -181,7 +188,7 @@ module('Acceptance | task fs', function(hooks) { ); await FS.breadcrumbs[1].visit(); - assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`); + assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name}`); assert.equal(FS.breadcrumbs.length, 2); }); @@ -319,7 +326,7 @@ module('Acceptance | task fs', function(hooks) { await FS.visitPath({ id: allocation.id, name: task.name, path: '/' }); - const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models); + const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, task.name).models); const fileRecord = sortedFiles.find(f => !f.isDir); const fileIndex = sortedFiles.indexOf(fileRecord); @@ -375,7 +382,7 @@ module('Acceptance | task fs', function(hooks) { return new Response(500, {}, 'no such file or directory'); }); - await FS.visitPath({ id: allocation.id, name: task.name, path: files[0].name }); + await FS.visitPath({ id: allocation.id, name: task.name, path: directory.name }); assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); await visit('/'); @@ -384,7 +391,7 @@ module('Acceptance | task fs', function(hooks) { return new Response(999); }); - await FS.visitPath({ id: allocation.id, name: task.name, path: files[0].name }); + await FS.visitPath({ id: allocation.id, name: task.name, path: directory.name }); assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); }); }); From 513739520799cc18789a727b909447715b6a53d5 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 19 May 2020 18:01:29 -0500 Subject: [PATCH 09/32] Fix path used for filesystem queries --- ui/app/routes/allocations/allocation/fs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/routes/allocations/allocation/fs.js b/ui/app/routes/allocations/allocation/fs.js index 2ccdba05850..f3580621a02 100644 --- a/ui/app/routes/allocations/allocation/fs.js +++ b/ui/app/routes/allocations/allocation/fs.js @@ -14,13 +14,13 @@ export default Route.extend({ }; } - return RSVP.all([allocation.stat(path), allocation.get('node')]) + return RSVP.all([allocation.stat(decodedPath), allocation.get('node')]) .then(([statJson]) => { if (statJson.IsDir) { return RSVP.hash({ path: decodedPath, allocation, - directoryEntries: allocation.ls(path).catch(notifyError(this)), + directoryEntries: allocation.ls(decodedPath).catch(notifyError(this)), isFile: false, }); } else { From c2062e9bb6805a7a67351d2a09c403999350d456 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Tue, 19 May 2020 18:05:18 -0500 Subject: [PATCH 10/32] Fix allocation breadcrumbs assertions --- ui/tests/acceptance/allocation-fs-test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index b7a744ce9b2..7c3d544db9a 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -126,7 +126,7 @@ module('Acceptance | allocation fs', function(hooks) { assert.equal(FS.breadcrumbs.length, 1); assert.ok(FS.breadcrumbs[0].isActive); - assert.equal(FS.breadcrumbs[0].text, 'task-name'); + assert.equal(FS.breadcrumbs[0].text, allocationShortId); FS.directoryEntries[0].as(directory => { const fileRecord = sortedFiles[0]; @@ -150,7 +150,7 @@ module('Acceptance | allocation fs', function(hooks) { assert.equal(FS.directoryEntries.length, 1); assert.equal(FS.breadcrumbs.length, 2); - assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`); + assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name}`); assert.notOk(FS.breadcrumbs[0].isActive); @@ -166,7 +166,7 @@ module('Acceptance | allocation fs', function(hooks) { ); assert.equal(FS.breadcrumbs.length, 3); - assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name} ${files[1].name}`); + assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name} ${files[1].name}`); assert.equal(FS.breadcrumbs[2].text, files[1].name); assert.notOk( @@ -179,7 +179,7 @@ module('Acceptance | allocation fs', function(hooks) { ); await FS.breadcrumbs[1].visit(); - assert.equal(FS.breadcrumbsText, `${task.name} ${files[0].name}`); + assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name}`); assert.equal(FS.breadcrumbs.length, 2); }); @@ -323,7 +323,7 @@ module('Acceptance | allocation fs', function(hooks) { await FS.directoryEntries[fileIndex].visit(); - assert.equal(FS.breadcrumbsText, `${task.name} ${fileRecord.name}`); + assert.equal(FS.breadcrumbsText, `${allocationShortId} ${fileRecord.name}`); assert.ok(FS.fileViewer.isPresent); From 8ae2fd51e0e04b85c3859918ad61ec220ef42178 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 20 May 2020 09:24:12 -0500 Subject: [PATCH 11/32] Remove logs link --- ui/app/templates/components/allocation-subnav.hbs | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/app/templates/components/allocation-subnav.hbs b/ui/app/templates/components/allocation-subnav.hbs index 679f1c6e4d8..14d47d58937 100644 --- a/ui/app/templates/components/allocation-subnav.hbs +++ b/ui/app/templates/components/allocation-subnav.hbs @@ -1,7 +1,6 @@
      • {{#link-to "allocations.allocation.index" allocation activeClass="is-active"}}Overview{{/link-to}}
      • - {{!--
      • {{#link-to "allocations.allocation.logs" allocation activeClass="is-active"}}Logs{{/link-to}}
      • --}}
      • {{#link-to "allocations.allocation.fs-root" allocation class=(if filesLinkActive "is-active")}}Files{{/link-to}}
      From 4781a590de455971437ab2621defceff9ce0354e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 27 May 2020 12:14:11 -0500 Subject: [PATCH 12/32] Add initial extraction of shared browsing tests --- ui/tests/acceptance/allocation-fs-test.js | 37 ++++++---------------- ui/tests/acceptance/behaviors/fs.js | 34 ++++++++++++++++++++ ui/tests/acceptance/task-fs-test.js | 38 +++++++---------------- 3 files changed, 55 insertions(+), 54 deletions(-) create mode 100644 ui/tests/acceptance/behaviors/fs.js diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index 7c3d544db9a..12bdda92210 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -10,6 +10,8 @@ import Response from 'ember-cli-mirage/response'; import { formatBytes } from 'nomad-ui/helpers/format-bytes'; import { filesForPath } from 'nomad-ui/mirage/config'; +import browseFilesystem from './behaviors/fs'; + import FS from 'nomad-ui/tests/pages/allocations/task/fs'; let allocation; @@ -42,6 +44,8 @@ module('Acceptance | allocation fs', function(hooks) { allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); allocationShortId = allocation.id.split('-')[0]; + this.allocation = allocation; + // Reset files files = []; @@ -84,33 +88,12 @@ module('Acceptance | allocation fs', function(hooks) { ); }); - test('visiting /allocations/:allocation_id/fs/:path', async function(assert) { - const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; - - const testPath = async filePath => { - let pathWithLeadingSlash = filePath; - - if (!pathWithLeadingSlash.startsWith('/')) { - pathWithLeadingSlash = `/${filePath}`; - } - - await FS.visitAllocationPath({ id: allocation.id, path: filePath }); - assert.equal( - currentURL(), - `/allocations/${allocation.id}/fs/${encodeURIComponent(filePath)}`, - 'No redirect' - ); - assert.equal( - document.title, - `${pathWithLeadingSlash} - Allocation ${allocationShortId} filesystem - Nomad` - ); - assert.equal(FS.breadcrumbsText, `${allocationShortId} ${filePath.replace(/\//g, ' ')}`.trim()); - }; - - await paths.reduce(async (prev, filePath) => { - await prev; - return testPath(filePath); - }, Promise.resolve()); + browseFilesystem({ + visitSegments: ({ allocation }) => ({ id: allocation.id }), + getExpectedPathBase: ({ allocation }) => `/allocations/${allocation.id}/fs/`, + getTitleComponent: ({ allocation }) => `Allocation ${allocation.id.split('-')[0]} filesystem`, + getBreadcrumbComponent: ({ allocation }) => allocation.id.split('-')[0], + pageObjectVisitPathFunctionName: 'visitAllocationPath', }); test('navigating allocation filesystem', async function(assert) { diff --git a/ui/tests/acceptance/behaviors/fs.js b/ui/tests/acceptance/behaviors/fs.js new file mode 100644 index 00000000000..152d74d3c4d --- /dev/null +++ b/ui/tests/acceptance/behaviors/fs.js @@ -0,0 +1,34 @@ +import { test } from 'qunit'; +import { currentURL } from '@ember/test-helpers'; +import FS from 'nomad-ui/tests/pages/allocations/task/fs'; + +export default function browseFilesystem({ pageObjectVisitPathFunctionName, visitSegments, getExpectedPathBase, getTitleComponent, getBreadcrumbComponent }) { + test('visiting filesystem paths', async function(assert) { + const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; + + const testPath = async filePath => { + let pathWithLeadingSlash = filePath; + + if (!pathWithLeadingSlash.startsWith('/')) { + pathWithLeadingSlash = `/${filePath}`; + } + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({allocation: this.allocation, task: this.task }), path: filePath }); + assert.equal( + currentURL(), + `${getExpectedPathBase({allocation: this.allocation, task: this.task })}${encodeURIComponent(filePath)}`, + 'No redirect' + ); + assert.equal( + document.title, + `${pathWithLeadingSlash} - ${getTitleComponent({allocation: this.allocation, task: this.task})} - Nomad` + ); + assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent({allocation: this.allocation, task: this.task})} ${filePath.replace(/\//g, ' ')}`.trim()); + }; + + await paths.reduce(async (prev, filePath) => { + await prev; + return testPath(filePath); + }, Promise.resolve()); + }); +} diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index 7c85adb0c54..41bb2c9cb5b 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -10,6 +10,8 @@ import Response from 'ember-cli-mirage/response'; import { formatBytes } from 'nomad-ui/helpers/format-bytes'; import { filesForPath } from 'nomad-ui/mirage/config'; +import browseFilesystem from './behaviors/fs'; + import FS from 'nomad-ui/tests/pages/allocations/task/fs'; let allocation; @@ -44,6 +46,9 @@ module('Acceptance | task fs', function(hooks) { task.name = 'task-name'; task.save(); + this.task = task; + this.allocation = allocation; + // Reset files files = []; @@ -93,33 +98,12 @@ module('Acceptance | task fs', function(hooks) { ); }); - test('visiting /allocations/:allocation_id/:task_name/fs/:path', async function(assert) { - const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; - - const testPath = async filePath => { - let pathWithLeadingSlash = filePath; - - if (!pathWithLeadingSlash.startsWith('/')) { - pathWithLeadingSlash = `/${filePath}`; - } - - await FS.visitPath({ id: allocation.id, name: task.name, path: filePath }); - assert.equal( - currentURL(), - `/allocations/${allocation.id}/${task.name}/fs/${encodeURIComponent(filePath)}`, - 'No redirect' - ); - assert.equal( - document.title, - `${pathWithLeadingSlash} - Task ${task.name} filesystem - Nomad` - ); - assert.equal(FS.breadcrumbsText, `${task.name} ${filePath.replace(/\//g, ' ')}`.trim()); - }; - - await paths.reduce(async (prev, filePath) => { - await prev; - return testPath(filePath); - }, Promise.resolve()); + browseFilesystem({ + visitSegments: ({allocation,task}) => ({ id: allocation.id, name: task.name }), + getExpectedPathBase: ({allocation,task}) => `/allocations/${allocation.id}/${task.name}/fs/`, + getTitleComponent: ({task}) => `Task ${task.name} filesystem`, + getBreadcrumbComponent: ({task}) => task.name, + pageObjectVisitPathFunctionName: 'visitPath', }); test('navigating allocation filesystem', async function(assert) { From d8760370ac444b66c9734b2cb7e8478e2136d4c1 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 27 May 2020 14:01:43 -0500 Subject: [PATCH 13/32] Extract more shared tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface here is still subpar, with the expectations of the various things dangling off `this.` (files? directory?), but maybe some cleanup is possible… --- ui/tests/acceptance/allocation-fs-test.js | 210 +------------------- ui/tests/acceptance/behaviors/fs.js | 225 +++++++++++++++++++++- ui/tests/acceptance/task-fs-test.js | 210 +------------------- 3 files changed, 233 insertions(+), 412 deletions(-) diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index 12bdda92210..37fe16d139f 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -1,5 +1,4 @@ -import { currentURL, visit } from '@ember/test-helpers'; -import { Promise } from 'rsvp'; +import { currentURL } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import moment from 'moment'; @@ -63,6 +62,9 @@ module('Acceptance | allocation fs', function(hooks) { files.push(server.create('allocFile', { isDir: true, name: 'empty-directory' })); files.push(server.create('allocFile', 'file', { fileType: 'txt' })); files.push(server.create('allocFile', 'file', { fileType: 'txt' })); + + this.files = files; + this.directory = files[0]; }); test('visiting /allocations/:allocation_id/fs', async function(assert) { @@ -93,6 +95,7 @@ module('Acceptance | allocation fs', function(hooks) { getExpectedPathBase: ({ allocation }) => `/allocations/${allocation.id}/fs/`, getTitleComponent: ({ allocation }) => `Allocation ${allocation.id.split('-')[0]} filesystem`, getBreadcrumbComponent: ({ allocation }) => allocation.id.split('-')[0], + getFilesystemRoot: () => '', pageObjectVisitPathFunctionName: 'visitAllocationPath', }); @@ -165,207 +168,4 @@ module('Acceptance | allocation fs', function(hooks) { assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name}`); assert.equal(FS.breadcrumbs.length, 2); }); - - test('sorting allocation filesystem directory', async function(assert) { - this.server.get('/client/fs/ls/:allocation_id', () => { - return [ - { - Name: 'aaa-big-old-file', - IsDir: false, - Size: 19190000, - ModTime: moment() - .subtract(1, 'year') - .format(), - }, - { - Name: 'mmm-small-mid-file', - IsDir: false, - Size: 1919, - ModTime: moment() - .subtract(6, 'month') - .format(), - }, - { - Name: 'zzz-med-new-file', - IsDir: false, - Size: 191900, - ModTime: moment().format(), - }, - { - Name: 'aaa-big-old-directory', - IsDir: true, - Size: 19190000, - ModTime: moment() - .subtract(1, 'year') - .format(), - }, - { - Name: 'mmm-small-mid-directory', - IsDir: true, - Size: 1919, - ModTime: moment() - .subtract(6, 'month') - .format(), - }, - { - Name: 'zzz-med-new-directory', - IsDir: true, - Size: 191900, - ModTime: moment().format(), - }, - ]; - }); - - await FS.visitAllocationPath({ id: allocation.id, path: '/' }); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'aaa-big-old-directory', - 'mmm-small-mid-directory', - 'zzz-med-new-directory', - 'aaa-big-old-file', - 'mmm-small-mid-file', - 'zzz-med-new-file', - ]); - - await FS.sortBy('Name'); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'zzz-med-new-file', - 'mmm-small-mid-file', - 'aaa-big-old-file', - 'zzz-med-new-directory', - 'mmm-small-mid-directory', - 'aaa-big-old-directory', - ]); - - await FS.sortBy('ModTime'); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'zzz-med-new-file', - 'mmm-small-mid-file', - 'aaa-big-old-file', - 'zzz-med-new-directory', - 'mmm-small-mid-directory', - 'aaa-big-old-directory', - ]); - - await FS.sortBy('ModTime'); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'aaa-big-old-directory', - 'mmm-small-mid-directory', - 'zzz-med-new-directory', - 'aaa-big-old-file', - 'mmm-small-mid-file', - 'zzz-med-new-file', - ]); - - await FS.sortBy('Size'); - - assert.deepEqual( - FS.directoryEntryNames(), - [ - 'aaa-big-old-file', - 'zzz-med-new-file', - 'mmm-small-mid-file', - 'zzz-med-new-directory', - 'mmm-small-mid-directory', - 'aaa-big-old-directory', - ], - 'expected files to be sorted by descending size and directories to be sorted by descending name' - ); - - await FS.sortBy('Size'); - - assert.deepEqual( - FS.directoryEntryNames(), - [ - 'aaa-big-old-directory', - 'mmm-small-mid-directory', - 'zzz-med-new-directory', - 'mmm-small-mid-file', - 'zzz-med-new-file', - 'aaa-big-old-file', - ], - 'expected directories to be sorted by name and files to be sorted by ascending size' - ); - }); - - test('viewing a file', async function(assert) { - const node = server.db.nodes.find(allocation.nodeId); - - server.get(`http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, function() { - return new Response(500); - }); - - await FS.visitAllocationPath({ id: allocation.id, path: '/' }); - - const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models); - const fileRecord = sortedFiles.find(f => !f.isDir); - const fileIndex = sortedFiles.indexOf(fileRecord); - - await FS.directoryEntries[fileIndex].visit(); - - assert.equal(FS.breadcrumbsText, `${allocationShortId} ${fileRecord.name}`); - - assert.ok(FS.fileViewer.isPresent); - - const requests = this.server.pretender.handledRequests; - const secondAttempt = requests.pop(); - const firstAttempt = requests.pop(); - - assert.equal( - firstAttempt.url.split('?')[0], - `//${node.httpAddr}/v1/client/fs/readat/${allocation.id}`, - 'Client is hit first' - ); - assert.equal(firstAttempt.status, 500, 'Client request fails'); - assert.equal( - secondAttempt.url.split('?')[0], - `/v1/client/fs/readat/${allocation.id}`, - 'Server is hit second' - ); - }); - - test('viewing an empty directory', async function(assert) { - await FS.visitAllocationPath({ id: allocation.id, path: 'empty-directory' }); - - assert.ok(FS.isEmptyDirectory); - }); - - test('viewing paths that produce stat API errors', async function(assert) { - this.server.get('/client/fs/stat/:allocation_id', () => { - return new Response(500, {}, 'no such file or directory'); - }); - - await FS.visitAllocationPath({ id: allocation.id, path: '/what-is-this' }); - assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); - - await visit('/'); - - this.server.get('/client/fs/stat/:allocation_id', () => { - return new Response(999); - }); - - await FS.visitAllocationPath({ id: allocation.id, path: '/what-is-this' }); - assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); - }); - - test('viewing paths that produce ls API errors', async function(assert) { - this.server.get('/client/fs/ls/:allocation_id', () => { - return new Response(500, {}, 'no such file or directory'); - }); - - await FS.visitAllocationPath({ id: allocation.id, path: files[0].name }); - assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); - - await visit('/'); - - this.server.get('/client/fs/ls/:allocation_id', () => { - return new Response(999); - }); - - await FS.visitAllocationPath({ id: allocation.id, path: files[0].name }); - assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); - }); }); diff --git a/ui/tests/acceptance/behaviors/fs.js b/ui/tests/acceptance/behaviors/fs.js index 152d74d3c4d..14e3dd367b1 100644 --- a/ui/tests/acceptance/behaviors/fs.js +++ b/ui/tests/acceptance/behaviors/fs.js @@ -1,8 +1,25 @@ import { test } from 'qunit'; -import { currentURL } from '@ember/test-helpers'; +import { currentURL, visit } from '@ember/test-helpers'; import FS from 'nomad-ui/tests/pages/allocations/task/fs'; +import moment from 'moment'; +import { filesForPath } from 'nomad-ui/mirage/config'; +import Response from 'ember-cli-mirage/response'; -export default function browseFilesystem({ pageObjectVisitPathFunctionName, visitSegments, getExpectedPathBase, getTitleComponent, getBreadcrumbComponent }) { +const fileSort = (prop, files) => { + let dir = []; + let file = []; + files.forEach(f => { + if (f.isDir) { + dir.push(f); + } else { + file.push(f); + } + }); + + return dir.sortBy(prop).concat(file.sortBy(prop)); +}; + +export default function browseFilesystem({ pageObjectVisitPathFunctionName, visitSegments, getExpectedPathBase, getTitleComponent, getBreadcrumbComponent, getFilesystemRoot }) { test('visiting filesystem paths', async function(assert) { const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; @@ -31,4 +48,208 @@ export default function browseFilesystem({ pageObjectVisitPathFunctionName, visi return testPath(filePath); }, Promise.resolve()); }); + + test('sorting allocation filesystem directory', async function(assert) { + this.server.get('/client/fs/ls/:allocation_id', () => { + return [ + { + Name: 'aaa-big-old-file', + IsDir: false, + Size: 19190000, + ModTime: moment() + .subtract(1, 'year') + .format(), + }, + { + Name: 'mmm-small-mid-file', + IsDir: false, + Size: 1919, + ModTime: moment() + .subtract(6, 'month') + .format(), + }, + { + Name: 'zzz-med-new-file', + IsDir: false, + Size: 191900, + ModTime: moment().format(), + }, + { + Name: 'aaa-big-old-directory', + IsDir: true, + Size: 19190000, + ModTime: moment() + .subtract(1, 'year') + .format(), + }, + { + Name: 'mmm-small-mid-directory', + IsDir: true, + Size: 1919, + ModTime: moment() + .subtract(6, 'month') + .format(), + }, + { + Name: 'zzz-med-new-directory', + IsDir: true, + Size: 191900, + ModTime: moment().format(), + }, + ]; + }); + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({allocation: this.allocation, task: this.task }), path: '/' }); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'aaa-big-old-directory', + 'mmm-small-mid-directory', + 'zzz-med-new-directory', + 'aaa-big-old-file', + 'mmm-small-mid-file', + 'zzz-med-new-file', + ]); + + await FS.sortBy('Name'); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'zzz-med-new-file', + 'mmm-small-mid-file', + 'aaa-big-old-file', + 'zzz-med-new-directory', + 'mmm-small-mid-directory', + 'aaa-big-old-directory', + ]); + + await FS.sortBy('ModTime'); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'zzz-med-new-file', + 'mmm-small-mid-file', + 'aaa-big-old-file', + 'zzz-med-new-directory', + 'mmm-small-mid-directory', + 'aaa-big-old-directory', + ]); + + await FS.sortBy('ModTime'); + + assert.deepEqual(FS.directoryEntryNames(), [ + 'aaa-big-old-directory', + 'mmm-small-mid-directory', + 'zzz-med-new-directory', + 'aaa-big-old-file', + 'mmm-small-mid-file', + 'zzz-med-new-file', + ]); + + await FS.sortBy('Size'); + + assert.deepEqual( + FS.directoryEntryNames(), + [ + 'aaa-big-old-file', + 'zzz-med-new-file', + 'mmm-small-mid-file', + 'zzz-med-new-directory', + 'mmm-small-mid-directory', + 'aaa-big-old-directory', + ], + 'expected files to be sorted by descending size and directories to be sorted by descending name' + ); + + await FS.sortBy('Size'); + + assert.deepEqual( + FS.directoryEntryNames(), + [ + 'aaa-big-old-directory', + 'mmm-small-mid-directory', + 'zzz-med-new-directory', + 'mmm-small-mid-file', + 'zzz-med-new-file', + 'aaa-big-old-file', + ], + 'expected directories to be sorted by name and files to be sorted by ascending size' + ); + }); + + test('viewing a file', async function(assert) { + const objects = { allocation: this.allocation, task: this.task }; + const node = server.db.nodes.find(this.allocation.nodeId); + + server.get(`http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, function() { + return new Response(500); + }); + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments(objects), path: '/' }); + + const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, getFilesystemRoot(objects)).models); + const fileRecord = sortedFiles.find(f => !f.isDir); + const fileIndex = sortedFiles.indexOf(fileRecord); + + await FS.directoryEntries[fileIndex].visit(); + + assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${fileRecord.name}`); + + assert.ok(FS.fileViewer.isPresent); + + const requests = this.server.pretender.handledRequests; + const secondAttempt = requests.pop(); + const firstAttempt = requests.pop(); + + assert.equal( + firstAttempt.url.split('?')[0], + `//${node.httpAddr}/v1/client/fs/readat/${this.allocation.id}`, + 'Client is hit first' + ); + assert.equal(firstAttempt.status, 500, 'Client request fails'); + assert.equal( + secondAttempt.url.split('?')[0], + `/v1/client/fs/readat/${this.allocation.id}`, + 'Server is hit second' + ); + }); + + test('viewing an empty directory', async function(assert) { + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: 'empty-directory' }); + + assert.ok(FS.isEmptyDirectory); + }); + + test('viewing paths that produce stat API errors', async function(assert) { + this.server.get('/client/fs/stat/:allocation_id', () => { + return new Response(500, {}, 'no such file or directory'); + }); + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: '/what-is-this' }); + assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); + + await visit('/'); + + this.server.get('/client/fs/stat/:allocation_id', () => { + return new Response(999); + }); + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: '/what-is-this' }); + assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); + }); + + test('viewing paths that produce ls API errors', async function(assert) { + this.server.get('/client/fs/ls/:allocation_id', () => { + return new Response(500, {}, 'no such file or directory'); + }); + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: this.directory.name }); + assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); + + await visit('/'); + + this.server.get('/client/fs/ls/:allocation_id', () => { + return new Response(999); + }); + + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments({ allocation: this.allocation, task: this.task }), path: this.directory.name }); + assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); + }); } diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index 41bb2c9cb5b..aa95fc14e74 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -1,5 +1,4 @@ -import { currentURL, visit } from '@ember/test-helpers'; -import { Promise } from 'rsvp'; +import { currentURL } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; import moment from 'moment'; @@ -73,6 +72,9 @@ module('Acceptance | task fs', function(hooks) { files.push(server.create('allocFile', { isDir: true, name: 'empty-directory', parent: taskDirectory })); files.push(server.create('allocFile', 'file', { fileType: 'txt', parent: taskDirectory })); files.push(server.create('allocFile', 'file', { fileType: 'txt', parent: taskDirectory })); + + this.files = files; + this.directory = directory; }); test('visiting /allocations/:allocation_id/:task_name/fs', async function(assert) { @@ -103,6 +105,7 @@ module('Acceptance | task fs', function(hooks) { getExpectedPathBase: ({allocation,task}) => `/allocations/${allocation.id}/${task.name}/fs/`, getTitleComponent: ({task}) => `Task ${task.name} filesystem`, getBreadcrumbComponent: ({task}) => task.name, + getFilesystemRoot: ({ task }) => task.name, pageObjectVisitPathFunctionName: 'visitPath', }); @@ -175,207 +178,4 @@ module('Acceptance | task fs', function(hooks) { assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name}`); assert.equal(FS.breadcrumbs.length, 2); }); - - test('sorting allocation filesystem directory', async function(assert) { - this.server.get('/client/fs/ls/:allocation_id', () => { - return [ - { - Name: 'aaa-big-old-file', - IsDir: false, - Size: 19190000, - ModTime: moment() - .subtract(1, 'year') - .format(), - }, - { - Name: 'mmm-small-mid-file', - IsDir: false, - Size: 1919, - ModTime: moment() - .subtract(6, 'month') - .format(), - }, - { - Name: 'zzz-med-new-file', - IsDir: false, - Size: 191900, - ModTime: moment().format(), - }, - { - Name: 'aaa-big-old-directory', - IsDir: true, - Size: 19190000, - ModTime: moment() - .subtract(1, 'year') - .format(), - }, - { - Name: 'mmm-small-mid-directory', - IsDir: true, - Size: 1919, - ModTime: moment() - .subtract(6, 'month') - .format(), - }, - { - Name: 'zzz-med-new-directory', - IsDir: true, - Size: 191900, - ModTime: moment().format(), - }, - ]; - }); - - await FS.visitPath({ id: allocation.id, name: task.name, path: '/' }); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'aaa-big-old-directory', - 'mmm-small-mid-directory', - 'zzz-med-new-directory', - 'aaa-big-old-file', - 'mmm-small-mid-file', - 'zzz-med-new-file', - ]); - - await FS.sortBy('Name'); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'zzz-med-new-file', - 'mmm-small-mid-file', - 'aaa-big-old-file', - 'zzz-med-new-directory', - 'mmm-small-mid-directory', - 'aaa-big-old-directory', - ]); - - await FS.sortBy('ModTime'); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'zzz-med-new-file', - 'mmm-small-mid-file', - 'aaa-big-old-file', - 'zzz-med-new-directory', - 'mmm-small-mid-directory', - 'aaa-big-old-directory', - ]); - - await FS.sortBy('ModTime'); - - assert.deepEqual(FS.directoryEntryNames(), [ - 'aaa-big-old-directory', - 'mmm-small-mid-directory', - 'zzz-med-new-directory', - 'aaa-big-old-file', - 'mmm-small-mid-file', - 'zzz-med-new-file', - ]); - - await FS.sortBy('Size'); - - assert.deepEqual( - FS.directoryEntryNames(), - [ - 'aaa-big-old-file', - 'zzz-med-new-file', - 'mmm-small-mid-file', - 'zzz-med-new-directory', - 'mmm-small-mid-directory', - 'aaa-big-old-directory', - ], - 'expected files to be sorted by descending size and directories to be sorted by descending name' - ); - - await FS.sortBy('Size'); - - assert.deepEqual( - FS.directoryEntryNames(), - [ - 'aaa-big-old-directory', - 'mmm-small-mid-directory', - 'zzz-med-new-directory', - 'mmm-small-mid-file', - 'zzz-med-new-file', - 'aaa-big-old-file', - ], - 'expected directories to be sorted by name and files to be sorted by ascending size' - ); - }); - - test('viewing a file', async function(assert) { - const node = server.db.nodes.find(allocation.nodeId); - - server.get(`http://${node.httpAddr}/v1/client/fs/readat/:allocation_id`, function() { - return new Response(500); - }); - - await FS.visitPath({ id: allocation.id, name: task.name, path: '/' }); - - const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, task.name).models); - const fileRecord = sortedFiles.find(f => !f.isDir); - const fileIndex = sortedFiles.indexOf(fileRecord); - - await FS.directoryEntries[fileIndex].visit(); - - assert.equal(FS.breadcrumbsText, `${task.name} ${fileRecord.name}`); - - assert.ok(FS.fileViewer.isPresent); - - const requests = this.server.pretender.handledRequests; - const secondAttempt = requests.pop(); - const firstAttempt = requests.pop(); - - assert.equal( - firstAttempt.url.split('?')[0], - `//${node.httpAddr}/v1/client/fs/readat/${allocation.id}`, - 'Client is hit first' - ); - assert.equal(firstAttempt.status, 500, 'Client request fails'); - assert.equal( - secondAttempt.url.split('?')[0], - `/v1/client/fs/readat/${allocation.id}`, - 'Server is hit second' - ); - }); - - test('viewing an empty directory', async function(assert) { - await FS.visitPath({ id: allocation.id, name: task.name, path: '/empty-directory' }); - - assert.ok(FS.isEmptyDirectory); - }); - - test('viewing paths that produce stat API errors', async function(assert) { - this.server.get('/client/fs/stat/:allocation_id', () => { - return new Response(500, {}, 'no such file or directory'); - }); - - await FS.visitPath({ id: allocation.id, name: task.name, path: '/what-is-this' }); - assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); - - await visit('/'); - - this.server.get('/client/fs/stat/:allocation_id', () => { - return new Response(999); - }); - - await FS.visitPath({ id: allocation.id, name: task.name, path: '/what-is-this' }); - assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); - }); - - test('viewing paths that produce ls API errors', async function(assert) { - this.server.get('/client/fs/ls/:allocation_id', () => { - return new Response(500, {}, 'no such file or directory'); - }); - - await FS.visitPath({ id: allocation.id, name: task.name, path: directory.name }); - assert.equal(FS.error.title, 'Not Found', '500 is interpreted as 404'); - - await visit('/'); - - this.server.get('/client/fs/ls/:allocation_id', () => { - return new Response(999); - }); - - await FS.visitPath({ id: allocation.id, name: task.name, path: directory.name }); - assert.equal(FS.error.title, 'Error', 'other statuses are passed through'); - }); }); From 96da7175cf34eac4644198986efe9ac3e939e0c8 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Wed, 27 May 2020 15:28:24 -0500 Subject: [PATCH 14/32] Extract all other tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There’s one left that has some duplication but it doesn’t seem worth extracting due to how much customisation it would require. --- ui/tests/acceptance/allocation-fs-test.js | 98 +---------------------- ui/tests/acceptance/behaviors/fs.js | 83 ++++++++++++++++++- ui/tests/acceptance/task-fs-test.js | 96 +--------------------- 3 files changed, 86 insertions(+), 191 deletions(-) diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index 37fe16d139f..d1afc8ac0c4 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -1,36 +1,16 @@ -import { currentURL } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; -import moment from 'moment'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import Response from 'ember-cli-mirage/response'; -import { formatBytes } from 'nomad-ui/helpers/format-bytes'; -import { filesForPath } from 'nomad-ui/mirage/config'; - import browseFilesystem from './behaviors/fs'; import FS from 'nomad-ui/tests/pages/allocations/task/fs'; let allocation; -let allocationShortId; let files; -const fileSort = (prop, files) => { - let dir = []; - let file = []; - files.forEach(f => { - if (f.isDir) { - dir.push(f); - } else { - file.push(f); - } - }); - - return dir.sortBy(prop).concat(file.sortBy(prop)); -}; - module('Acceptance | allocation fs', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); @@ -41,7 +21,6 @@ module('Acceptance | allocation fs', function(hooks) { const job = server.create('job', { createAllocations: false }); allocation = server.create('allocation', { jobId: job.id, clientStatus: 'running' }); - allocationShortId = allocation.id.split('-')[0]; this.allocation = allocation; @@ -65,11 +44,7 @@ module('Acceptance | allocation fs', function(hooks) { this.files = files; this.directory = files[0]; - }); - - test('visiting /allocations/:allocation_id/fs', async function(assert) { - await FS.visitAllocation({ id: allocation.id }); - assert.equal(currentURL(), `/allocations/${allocation.id}/fs`, 'No redirect'); + this.nestedDirectory = files[1]; }); test('when the allocation is not running, an empty state is shown', async function(assert) { @@ -96,76 +71,7 @@ module('Acceptance | allocation fs', function(hooks) { getTitleComponent: ({ allocation }) => `Allocation ${allocation.id.split('-')[0]} filesystem`, getBreadcrumbComponent: ({ allocation }) => allocation.id.split('-')[0], getFilesystemRoot: () => '', + pageObjectVisitFunctionName: 'visitAllocation', pageObjectVisitPathFunctionName: 'visitAllocationPath', }); - - test('navigating allocation filesystem', async function(assert) { - await FS.visitAllocationPath({ id: allocation.id, path: '/' }); - - const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, '').models); - - assert.ok(FS.fileViewer.isHidden); - - assert.equal(FS.directoryEntries.length, 4); - - assert.equal(FS.breadcrumbsText, allocationShortId); - - assert.equal(FS.breadcrumbs.length, 1); - assert.ok(FS.breadcrumbs[0].isActive); - assert.equal(FS.breadcrumbs[0].text, allocationShortId); - - FS.directoryEntries[0].as(directory => { - const fileRecord = sortedFiles[0]; - assert.equal(directory.name, fileRecord.name, 'directories should come first'); - assert.ok(directory.isDirectory); - assert.equal(directory.size, '', 'directory sizes are hidden'); - assert.equal(directory.lastModified, moment(fileRecord.modTime).fromNow()); - assert.notOk(directory.path.includes('//'), 'paths shouldn’t have redundant separators'); - }); - - FS.directoryEntries[2].as(file => { - const fileRecord = sortedFiles[2]; - assert.equal(file.name, fileRecord.name); - assert.ok(file.isFile); - assert.equal(file.size, formatBytes([fileRecord.size])); - assert.equal(file.lastModified, moment(fileRecord.modTime).fromNow()); - }); - - await FS.directoryEntries[0].visit(); - - assert.equal(FS.directoryEntries.length, 1); - - assert.equal(FS.breadcrumbs.length, 2); - assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name}`); - - assert.notOk(FS.breadcrumbs[0].isActive); - - assert.equal(FS.breadcrumbs[1].text, files[0].name); - assert.ok(FS.breadcrumbs[1].isActive); - - await FS.directoryEntries[0].visit(); - - assert.equal(FS.directoryEntries.length, 1); - assert.notOk( - FS.directoryEntries[0].path.includes('//'), - 'paths shouldn’t have redundant separators' - ); - - assert.equal(FS.breadcrumbs.length, 3); - assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name} ${files[1].name}`); - assert.equal(FS.breadcrumbs[2].text, files[1].name); - - assert.notOk( - FS.breadcrumbs[0].path.includes('//'), - 'paths shouldn’t have redundant separators' - ); - assert.notOk( - FS.breadcrumbs[1].path.includes('//'), - 'paths shouldn’t have redundant separators' - ); - - await FS.breadcrumbs[1].visit(); - assert.equal(FS.breadcrumbsText, `${allocationShortId} ${files[0].name}`); - assert.equal(FS.breadcrumbs.length, 2); - }); }); diff --git a/ui/tests/acceptance/behaviors/fs.js b/ui/tests/acceptance/behaviors/fs.js index 14e3dd367b1..47f2b07e245 100644 --- a/ui/tests/acceptance/behaviors/fs.js +++ b/ui/tests/acceptance/behaviors/fs.js @@ -4,6 +4,7 @@ import FS from 'nomad-ui/tests/pages/allocations/task/fs'; import moment from 'moment'; import { filesForPath } from 'nomad-ui/mirage/config'; import Response from 'ember-cli-mirage/response'; +import { formatBytes } from 'nomad-ui/helpers/format-bytes'; const fileSort = (prop, files) => { let dir = []; @@ -19,7 +20,16 @@ const fileSort = (prop, files) => { return dir.sortBy(prop).concat(file.sortBy(prop)); }; -export default function browseFilesystem({ pageObjectVisitPathFunctionName, visitSegments, getExpectedPathBase, getTitleComponent, getBreadcrumbComponent, getFilesystemRoot }) { +export default function browseFilesystem({ pageObjectVisitPathFunctionName, pageObjectVisitFunctionName, visitSegments, getExpectedPathBase, getTitleComponent, getBreadcrumbComponent, getFilesystemRoot }) { + test('visiting filesystem root', async function(assert) { + await FS[pageObjectVisitFunctionName](visitSegments({allocation: this.allocation, task: this.task })); + + const pathBaseWithTrailingSlash = getExpectedPathBase({ allocation: this.allocation, task: this.task }); + const pathBaseWithoutTrailingSlash = pathBaseWithTrailingSlash.slice(0, -1); + + assert.equal(currentURL(), pathBaseWithoutTrailingSlash, 'No redirect'); + }); + test('visiting filesystem paths', async function(assert) { const paths = ['some-file.log', 'a/deep/path/to/a/file.log', '/', 'Unicode™®']; @@ -49,6 +59,77 @@ export default function browseFilesystem({ pageObjectVisitPathFunctionName, visi }, Promise.resolve()); }); + test('navigating allocation filesystem', async function(assert) { + const objects = { allocation: this.allocation, task: this.task }; + await FS[pageObjectVisitPathFunctionName]({ ...visitSegments(objects), path: '/' }); + + const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, getFilesystemRoot(objects)).models); + + assert.ok(FS.fileViewer.isHidden); + + assert.equal(FS.directoryEntries.length, 4); + + assert.equal(FS.breadcrumbsText, getBreadcrumbComponent(objects)); + + assert.equal(FS.breadcrumbs.length, 1); + assert.ok(FS.breadcrumbs[0].isActive); + assert.equal(FS.breadcrumbs[0].text, getBreadcrumbComponent(objects)); + + FS.directoryEntries[0].as(directory => { + const fileRecord = sortedFiles[0]; + assert.equal(directory.name, fileRecord.name, 'directories should come first'); + assert.ok(directory.isDirectory); + assert.equal(directory.size, '', 'directory sizes are hidden'); + assert.equal(directory.lastModified, moment(fileRecord.modTime).fromNow()); + assert.notOk(directory.path.includes('//'), 'paths shouldn’t have redundant separators'); + }); + + FS.directoryEntries[2].as(file => { + const fileRecord = sortedFiles[2]; + assert.equal(file.name, fileRecord.name); + assert.ok(file.isFile); + assert.equal(file.size, formatBytes([fileRecord.size])); + assert.equal(file.lastModified, moment(fileRecord.modTime).fromNow()); + }); + + await FS.directoryEntries[0].visit(); + + assert.equal(FS.directoryEntries.length, 1); + + assert.equal(FS.breadcrumbs.length, 2); + assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${this.directory.name}`); + + assert.notOk(FS.breadcrumbs[0].isActive); + + assert.equal(FS.breadcrumbs[1].text, this.directory.name); + assert.ok(FS.breadcrumbs[1].isActive); + + await FS.directoryEntries[0].visit(); + + assert.equal(FS.directoryEntries.length, 1); + assert.notOk( + FS.directoryEntries[0].path.includes('//'), + 'paths shouldn’t have redundant separators' + ); + + assert.equal(FS.breadcrumbs.length, 3); + assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${this.directory.name} ${this.nestedDirectory.name}`); + assert.equal(FS.breadcrumbs[2].text, this.nestedDirectory.name); + + assert.notOk( + FS.breadcrumbs[0].path.includes('//'), + 'paths shouldn’t have redundant separators' + ); + assert.notOk( + FS.breadcrumbs[1].path.includes('//'), + 'paths shouldn’t have redundant separators' + ); + + await FS.breadcrumbs[1].visit(); + assert.equal(FS.breadcrumbsText, `${getBreadcrumbComponent(objects)} ${this.directory.name}`); + assert.equal(FS.breadcrumbs.length, 2); + }); + test('sorting allocation filesystem directory', async function(assert) { this.server.get('/client/fs/ls/:allocation_id', () => { return [ diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index aa95fc14e74..3f3194db59c 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -1,14 +1,9 @@ -import { currentURL } from '@ember/test-helpers'; import { module, test } from 'qunit'; import { setupApplicationTest } from 'ember-qunit'; -import moment from 'moment'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import Response from 'ember-cli-mirage/response'; -import { formatBytes } from 'nomad-ui/helpers/format-bytes'; -import { filesForPath } from 'nomad-ui/mirage/config'; - import browseFilesystem from './behaviors/fs'; import FS from 'nomad-ui/tests/pages/allocations/task/fs'; @@ -17,20 +12,6 @@ let allocation; let task; let files, taskDirectory, directory, nestedDirectory; -const fileSort = (prop, files) => { - let dir = []; - let file = []; - files.forEach(f => { - if (f.isDir) { - dir.push(f); - } else { - file.push(f); - } - }); - - return dir.sortBy(prop).concat(file.sortBy(prop)); -}; - module('Acceptance | task fs', function(hooks) { setupApplicationTest(hooks); setupMirage(hooks); @@ -75,11 +56,7 @@ module('Acceptance | task fs', function(hooks) { this.files = files; this.directory = directory; - }); - - test('visiting /allocations/:allocation_id/:task_name/fs', async function(assert) { - await FS.visit({ id: allocation.id, name: task.name }); - assert.equal(currentURL(), `/allocations/${allocation.id}/${task.name}/fs`, 'No redirect'); + this.nestedDirectory = nestedDirectory; }); test('when the task is not running, an empty state is shown', async function(assert) { @@ -106,76 +83,7 @@ module('Acceptance | task fs', function(hooks) { getTitleComponent: ({task}) => `Task ${task.name} filesystem`, getBreadcrumbComponent: ({task}) => task.name, getFilesystemRoot: ({ task }) => task.name, + pageObjectVisitFunctionName: 'visit', pageObjectVisitPathFunctionName: 'visitPath', }); - - test('navigating allocation filesystem', async function(assert) { - await FS.visitPath({ id: allocation.id, name: task.name, path: '/' }); - - const sortedFiles = fileSort('name', filesForPath(this.server.schema.allocFiles, task.name).models); - - assert.ok(FS.fileViewer.isHidden); - - assert.equal(FS.directoryEntries.length, 4); - - assert.equal(FS.breadcrumbsText, task.name); - - assert.equal(FS.breadcrumbs.length, 1); - assert.ok(FS.breadcrumbs[0].isActive); - assert.equal(FS.breadcrumbs[0].text, 'task-name'); - - FS.directoryEntries[0].as(directory => { - const fileRecord = sortedFiles[0]; - assert.equal(directory.name, fileRecord.name, 'directories should come first'); - assert.ok(directory.isDirectory); - assert.equal(directory.size, '', 'directory sizes are hidden'); - assert.equal(directory.lastModified, moment(fileRecord.modTime).fromNow()); - assert.notOk(directory.path.includes('//'), 'paths shouldn’t have redundant separators'); - }); - - FS.directoryEntries[2].as(file => { - const fileRecord = sortedFiles[2]; - assert.equal(file.name, fileRecord.name); - assert.ok(file.isFile); - assert.equal(file.size, formatBytes([fileRecord.size])); - assert.equal(file.lastModified, moment(fileRecord.modTime).fromNow()); - }); - - await FS.directoryEntries[0].visit(); - - assert.equal(FS.directoryEntries.length, 1); - - assert.equal(FS.breadcrumbs.length, 2); - assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name}`); - - assert.notOk(FS.breadcrumbs[0].isActive); - - assert.equal(FS.breadcrumbs[1].text, directory.name); - assert.ok(FS.breadcrumbs[1].isActive); - - await FS.directoryEntries[0].visit(); - - assert.equal(FS.directoryEntries.length, 1); - assert.notOk( - FS.directoryEntries[0].path.includes('//'), - 'paths shouldn’t have redundant separators' - ); - - assert.equal(FS.breadcrumbs.length, 3); - assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name} ${nestedDirectory.name}`); - assert.equal(FS.breadcrumbs[2].text, nestedDirectory.name); - - assert.notOk( - FS.breadcrumbs[0].path.includes('//'), - 'paths shouldn’t have redundant separators' - ); - assert.notOk( - FS.breadcrumbs[1].path.includes('//'), - 'paths shouldn’t have redundant separators' - ); - - await FS.breadcrumbs[1].visit(); - assert.equal(FS.breadcrumbsText, `${task.name} ${directory.name}`); - assert.equal(FS.breadcrumbs.length, 2); - }); }); From cc0d4916882bea65ffdea9158b68fccb6e84d723 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 08:51:06 -0500 Subject: [PATCH 15/32] Combine breadcrumbs components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Another combination could happen if I extract something like an fs-link component 🤔 --- ui/app/components/alloc-fs-breadcrumbs.js | 42 ------------------- ui/app/components/fs-breadcrumbs.js | 1 + .../templates/allocations/allocation/fs.hbs | 4 +- .../components/alloc-fs-breadcrumbs.hbs | 14 ------- .../templates/components/fs-breadcrumbs.hbs | 41 ++++++++++++------ 5 files changed, 32 insertions(+), 70 deletions(-) delete mode 100644 ui/app/components/alloc-fs-breadcrumbs.js delete mode 100644 ui/app/templates/components/alloc-fs-breadcrumbs.hbs diff --git a/ui/app/components/alloc-fs-breadcrumbs.js b/ui/app/components/alloc-fs-breadcrumbs.js deleted file mode 100644 index 87796df9400..00000000000 --- a/ui/app/components/alloc-fs-breadcrumbs.js +++ /dev/null @@ -1,42 +0,0 @@ -import Component from '@ember/component'; -import { computed } from '@ember/object'; -import { isEmpty } from '@ember/utils'; - -export default Component.extend({ - tagName: 'nav', - classNames: ['breadcrumb'], - - 'data-test-fs-breadcrumbs': true, - - allocation: null, - path: null, - - breadcrumbs: computed('path', function() { - const breadcrumbs = this.path - .split('/') - .reject(isEmpty) - .reduce((breadcrumbs, pathSegment, index) => { - let breadcrumbPath; - - if (index > 0) { - const lastBreadcrumb = breadcrumbs[index - 1]; - breadcrumbPath = `${lastBreadcrumb.path}/${pathSegment}`; - } else { - breadcrumbPath = pathSegment; - } - - breadcrumbs.push({ - name: pathSegment, - path: breadcrumbPath, - }); - - return breadcrumbs; - }, []); - - if (breadcrumbs.length) { - breadcrumbs[breadcrumbs.length - 1].isLast = true; - } - - return breadcrumbs; - }), -}); diff --git a/ui/app/components/fs-breadcrumbs.js b/ui/app/components/fs-breadcrumbs.js index f613a0c4933..9af6a73d505 100644 --- a/ui/app/components/fs-breadcrumbs.js +++ b/ui/app/components/fs-breadcrumbs.js @@ -8,6 +8,7 @@ export default Component.extend({ 'data-test-fs-breadcrumbs': true, + allocation: null, task: null, path: null, diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index f59b453d449..7412e7876f4 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -4,12 +4,12 @@ {{#if allocation.isRunning}} {{#if isFile}} {{#task-file allocation=allocation file=path stat=stat class="fs-explorer"}} - {{alloc-fs-breadcrumbs allocation=allocation path=path}} + {{fs-breadcrumbs allocation=allocation path=path}} {{/task-file}} {{else}}
      - {{alloc-fs-breadcrumbs allocation=allocation path=path}} + {{fs-breadcrumbs allocation=allocation path=path}}
      {{#if directoryEntries}} {{#list-table diff --git a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs b/ui/app/templates/components/alloc-fs-breadcrumbs.hbs deleted file mode 100644 index 4f2701ebe42..00000000000 --- a/ui/app/templates/components/alloc-fs-breadcrumbs.hbs +++ /dev/null @@ -1,14 +0,0 @@ -
        -
      • - {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} - {{allocation.shortId}} - {{/link-to}} -
      • - {{#each breadcrumbs as |breadcrumb|}} -
      • - {{#link-to "allocations.allocation.fs" allocation breadcrumb.path activeClass="is-active"}} - {{breadcrumb.name}} - {{/link-to}} -
      • - {{/each}} -
      \ No newline at end of file diff --git a/ui/app/templates/components/fs-breadcrumbs.hbs b/ui/app/templates/components/fs-breadcrumbs.hbs index 97aba6398a5..a7b66b6ff4f 100644 --- a/ui/app/templates/components/fs-breadcrumbs.hbs +++ b/ui/app/templates/components/fs-breadcrumbs.hbs @@ -1,14 +1,31 @@ -
        -
      • - {{#link-to "allocations.allocation.task.fs-root" task.allocation task activeClass="is-active"}} - {{task.name}} - {{/link-to}} -
      • - {{#each breadcrumbs as |breadcrumb|}} -
      • - {{#link-to "allocations.allocation.task.fs" task.allocation task breadcrumb.path activeClass="is-active"}} - {{breadcrumb.name}} +{{#if task}} +
          +
        • + {{#link-to "allocations.allocation.task.fs-root" task.allocation task activeClass="is-active"}} + {{task.name}} {{/link-to}}
        • - {{/each}} -
        \ No newline at end of file + {{#each breadcrumbs as |breadcrumb|}} +
      • + {{#link-to "allocations.allocation.task.fs" task.allocation task breadcrumb.path activeClass="is-active"}} + {{breadcrumb.name}} + {{/link-to}} +
      • + {{/each}} +
      +{{else}} +
        +
      • + {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} + {{allocation.shortId}} + {{/link-to}} +
      • + {{#each breadcrumbs as |breadcrumb|}} +
      • + {{#link-to "allocations.allocation.fs" allocation breadcrumb.path activeClass="is-active"}} + {{breadcrumb.name}} + {{/link-to}} +
      • + {{/each}} +
      +{{/if}} \ No newline at end of file From d3df8c56f390e710feed96e14b135a5f6b094b3c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 08:58:27 -0500 Subject: [PATCH 16/32] Add note about task file error text --- ui/app/templates/components/task-file.hbs | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/templates/components/task-file.hbs b/ui/app/templates/components/task-file.hbs index bed5c27620f..ecf9cae4ea3 100644 --- a/ui/app/templates/components/task-file.hbs +++ b/ui/app/templates/components/task-file.hbs @@ -2,6 +2,7 @@

      Cannot fetch file

      The files for this task are inaccessible. Check the condition of the client the allocation is on.

      +
      {{/if}}
      From 4b77ffba05ec3ae7da2194b214c174c125da2f41 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 09:09:07 -0500 Subject: [PATCH 17/32] Change task-file interface to be more generic --- ui/app/components/task-file.js | 17 +++++++++++++++-- ui/app/templates/allocations/allocation/fs.hbs | 2 +- .../allocations/allocation/task/fs.hbs | 2 +- ui/tests/integration/task-file-test.js | 10 ++++++++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ui/app/components/task-file.js b/ui/app/components/task-file.js index 438b8d62470..5ff705793a7 100644 --- a/ui/app/components/task-file.js +++ b/ui/app/components/task-file.js @@ -14,8 +14,7 @@ export default Component.extend({ 'data-test-file-viewer': true, - allocation: null, - task: null, + model: null, file: null, stat: null, // { Name, IsDir, Size, FileMode, ModTime, ContentType } @@ -30,6 +29,20 @@ export default Component.extend({ mode: 'head', + allocation: computed('model', function() { + if (this.model.allocation) { + return this.model.allocation; + } else { + return this.model; + } + }), + + task: computed('model', function() { + if (this.model.allocation) { + return this.model; + } + }), + fileComponent: computed('stat.ContentType', function() { const contentType = this.stat.ContentType || ''; diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index 7412e7876f4..68dcfbdfded 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -3,7 +3,7 @@
      {{#if allocation.isRunning}} {{#if isFile}} - {{#task-file allocation=allocation file=path stat=stat class="fs-explorer"}} + {{#task-file model=allocation file=path stat=stat class="fs-explorer"}} {{fs-breadcrumbs allocation=allocation path=path}} {{/task-file}} {{else}} diff --git a/ui/app/templates/allocations/allocation/task/fs.hbs b/ui/app/templates/allocations/allocation/task/fs.hbs index 45a6b437efa..4d6c94e22a7 100644 --- a/ui/app/templates/allocations/allocation/task/fs.hbs +++ b/ui/app/templates/allocations/allocation/task/fs.hbs @@ -3,7 +3,7 @@
      {{#if task.isRunning}} {{#if isFile}} - {{#task-file allocation=task.allocation task=task file=path stat=stat class="fs-explorer"}} + {{#task-file model=task file=path stat=stat class="fs-explorer"}} {{fs-breadcrumbs task=task path=path}} {{/task-file}} {{else}} diff --git a/ui/tests/integration/task-file-test.js b/ui/tests/integration/task-file-test.js index 47a89ade441..fd556b4229b 100644 --- a/ui/tests/integration/task-file-test.js +++ b/ui/tests/integration/task-file-test.js @@ -25,7 +25,7 @@ module('Integration | Component | task file', function(hooks) { }); const commonTemplate = hbs` - {{task-file allocation=allocation task=task file=file stat=stat}} + {{task-file model=task file=file stat=stat}} `; const fileStat = (type, size = 0) => ({ @@ -46,6 +46,12 @@ module('Integration | Component | task file', function(hooks) { }, task: { name: 'task-name', + allocation: { + id: 'alloc-1', + node: { + httpAddr: HOST, + }, + }, }, file: 'path/to/file', stat: { @@ -184,7 +190,7 @@ module('Integration | Component | task file', function(hooks) { this.setProperties(props); await render(hbs` - {{#task-file allocation=allocation task=task file=file stat=stat}} + {{#task-file model=task file=file stat=stat}}
      Yielded content
      {{/task-file}} `); From 1e33b692adb4c9efba45381b2e9dc8d56ebbfa3e Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 09:11:35 -0500 Subject: [PATCH 18/32] =?UTF-8?q?Change=20fs-directory=E2=80=A6=20interfac?= =?UTF-8?q?e=20to=20be=20more=20generic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/app/components/fs-directory-entry.js | 16 ++++++++++++++++ ui/app/templates/allocations/allocation/fs.hbs | 2 +- .../templates/allocations/allocation/task/fs.hbs | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/ui/app/components/fs-directory-entry.js b/ui/app/components/fs-directory-entry.js index f50bb84560d..d43e5f92068 100644 --- a/ui/app/components/fs-directory-entry.js +++ b/ui/app/components/fs-directory-entry.js @@ -5,6 +5,22 @@ import { isEmpty } from '@ember/utils'; export default Component.extend({ tagName: '', + model: null, + + allocation: computed('model', function() { + if (this.model.allocation) { + return this.model.allocation; + } else { + return this.model; + } + }), + + task: computed('model', function() { + if (this.model.allocation) { + return this.model; + } + }), + pathToEntry: computed('path', 'entry.Name', function() { const pathWithNoLeadingSlash = this.get('path').replace(/^\//, ''); const name = encodeURIComponent(this.get('entry.Name')); diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index 68dcfbdfded..fca2fd547b4 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -23,7 +23,7 @@ {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} {{/t.head}} {{#t.body as |row|}} - {{fs-directory-entry path=path allocation=allocation entry=row.model}} + {{fs-directory-entry path=path model=allocation entry=row.model}} {{/t.body}} {{/list-table}} {{else}} diff --git a/ui/app/templates/allocations/allocation/task/fs.hbs b/ui/app/templates/allocations/allocation/task/fs.hbs index 4d6c94e22a7..5058698cdfd 100644 --- a/ui/app/templates/allocations/allocation/task/fs.hbs +++ b/ui/app/templates/allocations/allocation/task/fs.hbs @@ -23,7 +23,7 @@ {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} {{/t.head}} {{#t.body as |row|}} - {{fs-directory-entry path=path task=task entry=row.model}} + {{fs-directory-entry path=path model=task entry=row.model}} {{/t.body}} {{/list-table}} {{else}} From 8e4f35226456ea456defddf023de88c36de68c28 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 09:45:52 -0500 Subject: [PATCH 19/32] Extract fs-browser component --- ui/app/components/fs-browser.js | 57 +++++++++++++++++++ ui/app/components/fs-directory-entry.js | 4 +- .../controllers/allocations/allocation/fs.js | 26 --------- .../allocations/allocation/task/fs.js | 26 --------- .../templates/allocations/allocation/fs.hbs | 48 +--------------- .../allocations/allocation/task/fs.hbs | 48 +--------------- ui/app/templates/components/fs-browser.hbs | 47 +++++++++++++++ 7 files changed, 108 insertions(+), 148 deletions(-) create mode 100644 ui/app/components/fs-browser.js create mode 100644 ui/app/templates/components/fs-browser.hbs diff --git a/ui/app/components/fs-browser.js b/ui/app/components/fs-browser.js new file mode 100644 index 00000000000..453a6aabc9e --- /dev/null +++ b/ui/app/components/fs-browser.js @@ -0,0 +1,57 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; +import { filterBy } from '@ember/object/computed'; + +export default Component.extend({ + tagName: '', + + model: null, + + allocation: computed('model', function() { + if (this.model.allocation) { + return this.model.allocation; + } else { + return this.model; + } + }), + + task: computed('model', function() { + if (this.model.allocation) { + return this.model; + } + }), + + type: computed('task', function() { + if (this.task) { + return 'task'; + } else { + return 'allocation'; + } + }), + + directories: filterBy('directoryEntries', 'IsDir'), + files: filterBy('directoryEntries', 'IsDir', false), + + sortedDirectoryEntries: computed( + 'directoryEntries.[]', + 'sortProperty', + 'sortDescending', + function() { + const sortProperty = this.sortProperty; + + const directorySortProperty = sortProperty === 'Size' ? 'Name' : sortProperty; + + const sortedDirectories = this.directories.sortBy(directorySortProperty); + const sortedFiles = this.files.sortBy(sortProperty); + + const sortedDirectoryEntries = sortedDirectories.concat(sortedFiles); + + if (this.sortDescending) { + return sortedDirectoryEntries.reverse(); + } else { + return sortedDirectoryEntries; + } + } + ), + +}); diff --git a/ui/app/components/fs-directory-entry.js b/ui/app/components/fs-directory-entry.js index d43e5f92068..782624901d6 100644 --- a/ui/app/components/fs-directory-entry.js +++ b/ui/app/components/fs-directory-entry.js @@ -8,7 +8,7 @@ export default Component.extend({ model: null, allocation: computed('model', function() { - if (this.model.allocation) { + if (this.model && this.model.allocation) { return this.model.allocation; } else { return this.model; @@ -16,7 +16,7 @@ export default Component.extend({ }), task: computed('model', function() { - if (this.model.allocation) { + if (this.model && this.model.allocation) { return this.model; } }), diff --git a/ui/app/controllers/allocations/allocation/fs.js b/ui/app/controllers/allocations/allocation/fs.js index 328c104e9fc..745eeb9d02b 100644 --- a/ui/app/controllers/allocations/allocation/fs.js +++ b/ui/app/controllers/allocations/allocation/fs.js @@ -1,6 +1,5 @@ import Controller from '@ember/controller'; import { computed } from '@ember/object'; -import { filterBy } from '@ember/object/computed'; export default Controller.extend({ queryParams: { @@ -17,9 +16,6 @@ export default Controller.extend({ isFile: null, stat: null, - directories: filterBy('directoryEntries', 'IsDir'), - files: filterBy('directoryEntries', 'IsDir', false), - pathWithLeadingSlash: computed('path', function() { const path = this.path; @@ -29,26 +25,4 @@ export default Controller.extend({ return `/${path}`; } }), - - sortedDirectoryEntries: computed( - 'directoryEntries.[]', - 'sortProperty', - 'sortDescending', - function() { - const sortProperty = this.sortProperty; - - const directorySortProperty = sortProperty === 'Size' ? 'Name' : sortProperty; - - const sortedDirectories = this.directories.sortBy(directorySortProperty); - const sortedFiles = this.files.sortBy(sortProperty); - - const sortedDirectoryEntries = sortedDirectories.concat(sortedFiles); - - if (this.sortDescending) { - return sortedDirectoryEntries.reverse(); - } else { - return sortedDirectoryEntries; - } - } - ), }); diff --git a/ui/app/controllers/allocations/allocation/task/fs.js b/ui/app/controllers/allocations/allocation/task/fs.js index bfece091338..a0c3b5e697a 100644 --- a/ui/app/controllers/allocations/allocation/task/fs.js +++ b/ui/app/controllers/allocations/allocation/task/fs.js @@ -1,6 +1,5 @@ import Controller from '@ember/controller'; import { computed } from '@ember/object'; -import { filterBy } from '@ember/object/computed'; export default Controller.extend({ queryParams: { @@ -17,9 +16,6 @@ export default Controller.extend({ isFile: null, stat: null, - directories: filterBy('directoryEntries', 'IsDir'), - files: filterBy('directoryEntries', 'IsDir', false), - pathWithLeadingSlash: computed('path', function() { const path = this.path; @@ -29,26 +25,4 @@ export default Controller.extend({ return `/${path}`; } }), - - sortedDirectoryEntries: computed( - 'directoryEntries.[]', - 'sortProperty', - 'sortDescending', - function() { - const sortProperty = this.sortProperty; - - const directorySortProperty = sortProperty === 'Size' ? 'Name' : sortProperty; - - const sortedDirectories = this.directories.sortBy(directorySortProperty); - const sortedFiles = this.files.sortBy(sortProperty); - - const sortedDirectoryEntries = sortedDirectories.concat(sortedFiles); - - if (this.sortDescending) { - return sortedDirectoryEntries.reverse(); - } else { - return sortedDirectoryEntries; - } - } - ), }); diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index fca2fd547b4..90f9f81d513 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -1,49 +1,3 @@ {{title pathWithLeadingSlash " - Allocation " allocation.shortId " filesystem"}} {{allocation-subnav allocation=allocation}} -
      - {{#if allocation.isRunning}} - {{#if isFile}} - {{#task-file model=allocation file=path stat=stat class="fs-explorer"}} - {{fs-breadcrumbs allocation=allocation path=path}} - {{/task-file}} - {{else}} -
      -
      - {{fs-breadcrumbs allocation=allocation path=path}} -
      - {{#if directoryEntries}} - {{#list-table - source=sortedDirectoryEntries - sortProperty=sortProperty - sortDescending=sortDescending - class="boxed-section-body is-full-bleed is-compact" as |t|}} - {{#t.head}} - {{#t.sort-by prop="Name" class="is-two-thirds"}}Name{{/t.sort-by}} - {{#t.sort-by prop="Size" class="has-text-right"}}File Size{{/t.sort-by}} - {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} - {{/t.head}} - {{#t.body as |row|}} - {{fs-directory-entry path=path model=allocation entry=row.model}} - {{/t.body}} - {{/list-table}} - {{else}} -
      -
      -

      No Files

      -

      - Directory is currently empty. -

      -
      -
      - {{/if}} -
      - {{/if}} - {{else}} -
      -

      Allocation is not Running

      -

      - Cannot access files of an allocation that is not running. -

      -
      - {{/if}} -
      +{{fs-browser model=allocation path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} diff --git a/ui/app/templates/allocations/allocation/task/fs.hbs b/ui/app/templates/allocations/allocation/task/fs.hbs index 5058698cdfd..4031bb52e9d 100644 --- a/ui/app/templates/allocations/allocation/task/fs.hbs +++ b/ui/app/templates/allocations/allocation/task/fs.hbs @@ -1,49 +1,3 @@ {{title pathWithLeadingSlash " - Task " task.name " filesystem"}} {{task-subnav task=task}} -
      - {{#if task.isRunning}} - {{#if isFile}} - {{#task-file model=task file=path stat=stat class="fs-explorer"}} - {{fs-breadcrumbs task=task path=path}} - {{/task-file}} - {{else}} -
      -
      - {{fs-breadcrumbs task=task path=path}} -
      - {{#if directoryEntries}} - {{#list-table - source=sortedDirectoryEntries - sortProperty=sortProperty - sortDescending=sortDescending - class="boxed-section-body is-full-bleed is-compact" as |t|}} - {{#t.head}} - {{#t.sort-by prop="Name" class="is-two-thirds"}}Name{{/t.sort-by}} - {{#t.sort-by prop="Size" class="has-text-right"}}File Size{{/t.sort-by}} - {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} - {{/t.head}} - {{#t.body as |row|}} - {{fs-directory-entry path=path model=task entry=row.model}} - {{/t.body}} - {{/list-table}} - {{else}} -
      -
      -

      No Files

      -

      - Directory is currently empty. -

      -
      -
      - {{/if}} -
      - {{/if}} - {{else}} -
      -

      Task is not Running

      -

      - Cannot access files of a task that is not running. -

      -
      - {{/if}} -
      +{{fs-browser model=task path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} \ No newline at end of file diff --git a/ui/app/templates/components/fs-browser.hbs b/ui/app/templates/components/fs-browser.hbs new file mode 100644 index 00000000000..f42be50588a --- /dev/null +++ b/ui/app/templates/components/fs-browser.hbs @@ -0,0 +1,47 @@ +
      + {{#if model.isRunning}} + {{#if isFile}} + {{#task-file model=model file=path stat=stat class="fs-explorer"}} + {{fs-breadcrumbs allocation=allocation task=task path=path}} + {{/task-file}} + {{else}} +
      +
      + {{fs-breadcrumbs allocation=allocation task=task path=path}} +
      + {{#if directoryEntries}} + {{#list-table + source=sortedDirectoryEntries + sortProperty=sortProperty + sortDescending=sortDescending + class="boxed-section-body is-full-bleed is-compact" as |t|}} + {{#t.head}} + {{#t.sort-by prop="Name" class="is-two-thirds"}}Name{{/t.sort-by}} + {{#t.sort-by prop="Size" class="has-text-right"}}File Size{{/t.sort-by}} + {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} + {{/t.head}} + {{#t.body as |row|}} + {{fs-directory-entry path=path model=model entry=row.model}} + {{/t.body}} + {{/list-table}} + {{else}} +
      +
      +

      No Files

      +

      + Directory is currently empty. +

      +
      +
      + {{/if}} +
      + {{/if}} + {{else}} +
      +

      {{capitalize type}} is not Running

      +

      + Cannot access files of a{{if allocation 'n'}} {{type}} that is not running. +

      +
      + {{/if}} +
      From 2ed5c43ca64a97d8aaf56510b79cf0cc990c48ed Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 09:49:55 -0500 Subject: [PATCH 20/32] Move fs components into their own directory --- ui/app/components/{fs-breadcrumbs.js => fs/breadcrumbs.js} | 0 ui/app/components/{fs-browser.js => fs/browser.js} | 0 .../{fs-directory-entry.js => fs/directory-entry.js} | 0 ui/app/templates/allocations/allocation/fs.hbs | 2 +- ui/app/templates/allocations/allocation/task/fs.hbs | 2 +- .../components/{fs-breadcrumbs.hbs => fs/breadcrumbs.hbs} | 0 .../templates/components/{fs-browser.hbs => fs/browser.hbs} | 6 +++--- .../{fs-directory-entry.hbs => fs/directory-entry.hbs} | 0 8 files changed, 5 insertions(+), 5 deletions(-) rename ui/app/components/{fs-breadcrumbs.js => fs/breadcrumbs.js} (100%) rename ui/app/components/{fs-browser.js => fs/browser.js} (100%) rename ui/app/components/{fs-directory-entry.js => fs/directory-entry.js} (100%) rename ui/app/templates/components/{fs-breadcrumbs.hbs => fs/breadcrumbs.hbs} (100%) rename ui/app/templates/components/{fs-browser.hbs => fs/browser.hbs} (90%) rename ui/app/templates/components/{fs-directory-entry.hbs => fs/directory-entry.hbs} (100%) diff --git a/ui/app/components/fs-breadcrumbs.js b/ui/app/components/fs/breadcrumbs.js similarity index 100% rename from ui/app/components/fs-breadcrumbs.js rename to ui/app/components/fs/breadcrumbs.js diff --git a/ui/app/components/fs-browser.js b/ui/app/components/fs/browser.js similarity index 100% rename from ui/app/components/fs-browser.js rename to ui/app/components/fs/browser.js diff --git a/ui/app/components/fs-directory-entry.js b/ui/app/components/fs/directory-entry.js similarity index 100% rename from ui/app/components/fs-directory-entry.js rename to ui/app/components/fs/directory-entry.js diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index 90f9f81d513..6c4c7b9541f 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -1,3 +1,3 @@ {{title pathWithLeadingSlash " - Allocation " allocation.shortId " filesystem"}} {{allocation-subnav allocation=allocation}} -{{fs-browser model=allocation path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} +{{fs/browser model=allocation path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} diff --git a/ui/app/templates/allocations/allocation/task/fs.hbs b/ui/app/templates/allocations/allocation/task/fs.hbs index 4031bb52e9d..d6b10f19b04 100644 --- a/ui/app/templates/allocations/allocation/task/fs.hbs +++ b/ui/app/templates/allocations/allocation/task/fs.hbs @@ -1,3 +1,3 @@ {{title pathWithLeadingSlash " - Task " task.name " filesystem"}} {{task-subnav task=task}} -{{fs-browser model=task path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} \ No newline at end of file +{{fs/browser model=task path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} \ No newline at end of file diff --git a/ui/app/templates/components/fs-breadcrumbs.hbs b/ui/app/templates/components/fs/breadcrumbs.hbs similarity index 100% rename from ui/app/templates/components/fs-breadcrumbs.hbs rename to ui/app/templates/components/fs/breadcrumbs.hbs diff --git a/ui/app/templates/components/fs-browser.hbs b/ui/app/templates/components/fs/browser.hbs similarity index 90% rename from ui/app/templates/components/fs-browser.hbs rename to ui/app/templates/components/fs/browser.hbs index f42be50588a..875dab49865 100644 --- a/ui/app/templates/components/fs-browser.hbs +++ b/ui/app/templates/components/fs/browser.hbs @@ -2,12 +2,12 @@ {{#if model.isRunning}} {{#if isFile}} {{#task-file model=model file=path stat=stat class="fs-explorer"}} - {{fs-breadcrumbs allocation=allocation task=task path=path}} + {{fs/breadcrumbs allocation=allocation task=task path=path}} {{/task-file}} {{else}}
      - {{fs-breadcrumbs allocation=allocation task=task path=path}} + {{fs/breadcrumbs allocation=allocation task=task path=path}}
      {{#if directoryEntries}} {{#list-table @@ -21,7 +21,7 @@ {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} {{/t.head}} {{#t.body as |row|}} - {{fs-directory-entry path=path model=model entry=row.model}} + {{fs/directory-entry path=path model=model entry=row.model}} {{/t.body}} {{/list-table}} {{else}} diff --git a/ui/app/templates/components/fs-directory-entry.hbs b/ui/app/templates/components/fs/directory-entry.hbs similarity index 100% rename from ui/app/templates/components/fs-directory-entry.hbs rename to ui/app/templates/components/fs/directory-entry.hbs From 891b92949bda60f9b15acd5c82b6e5a90789f330 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 10:17:17 -0500 Subject: [PATCH 21/32] Extract fs link component This contains some of the duplication scattered about where filesystem links are slightly different in two dimensions. --- ui/app/components/fs/directory-entry.js | 14 ------ ui/app/components/fs/link.js | 22 ++++++++++ .../templates/components/fs/breadcrumbs.hbs | 43 ++++++------------- .../components/fs/directory-entry.hbs | 28 ++++-------- ui/app/templates/components/fs/link.hbs | 21 +++++++++ 5 files changed, 64 insertions(+), 64 deletions(-) create mode 100644 ui/app/components/fs/link.js create mode 100644 ui/app/templates/components/fs/link.hbs diff --git a/ui/app/components/fs/directory-entry.js b/ui/app/components/fs/directory-entry.js index 782624901d6..da9044c0a44 100644 --- a/ui/app/components/fs/directory-entry.js +++ b/ui/app/components/fs/directory-entry.js @@ -7,20 +7,6 @@ export default Component.extend({ model: null, - allocation: computed('model', function() { - if (this.model && this.model.allocation) { - return this.model.allocation; - } else { - return this.model; - } - }), - - task: computed('model', function() { - if (this.model && this.model.allocation) { - return this.model; - } - }), - pathToEntry: computed('path', 'entry.Name', function() { const pathWithNoLeadingSlash = this.get('path').replace(/^\//, ''); const name = encodeURIComponent(this.get('entry.Name')); diff --git a/ui/app/components/fs/link.js b/ui/app/components/fs/link.js new file mode 100644 index 00000000000..a48a9b49044 --- /dev/null +++ b/ui/app/components/fs/link.js @@ -0,0 +1,22 @@ +import Component from '@ember/component'; +import { computed } from '@ember/object'; + +export default Component.extend({ + tagName: '', + + model: null, + + allocation: computed('model', function() { + if (this.model && this.model.allocation) { + return this.model.allocation; + } else { + return this.model; + } + }), + + task: computed('model', function() { + if (this.model && this.model.allocation) { + return this.model; + } + }), +}); diff --git a/ui/app/templates/components/fs/breadcrumbs.hbs b/ui/app/templates/components/fs/breadcrumbs.hbs index a7b66b6ff4f..c2b27ef625a 100644 --- a/ui/app/templates/components/fs/breadcrumbs.hbs +++ b/ui/app/templates/components/fs/breadcrumbs.hbs @@ -1,31 +1,14 @@ -{{#if task}} -
        -
      • - {{#link-to "allocations.allocation.task.fs-root" task.allocation task activeClass="is-active"}} - {{task.name}} - {{/link-to}} +
          +
        • + {{#fs/link model=(if task task allocation)}} + {{if task task.name allocation.shortId}} + {{/fs/link}} +
        • + {{#each breadcrumbs as |breadcrumb|}} +
        • + {{#fs/link model=(if task task allocation) path=breadcrumb.path}} + {{breadcrumb.name}} + {{/fs/link}}
        • - {{#each breadcrumbs as |breadcrumb|}} -
        • - {{#link-to "allocations.allocation.task.fs" task.allocation task breadcrumb.path activeClass="is-active"}} - {{breadcrumb.name}} - {{/link-to}} -
        • - {{/each}} -
        -{{else}} -
          -
        • - {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} - {{allocation.shortId}} - {{/link-to}} -
        • - {{#each breadcrumbs as |breadcrumb|}} -
        • - {{#link-to "allocations.allocation.fs" allocation breadcrumb.path activeClass="is-active"}} - {{breadcrumb.name}} - {{/link-to}} -
        • - {{/each}} -
        -{{/if}} \ No newline at end of file + {{/each}} +
      diff --git a/ui/app/templates/components/fs/directory-entry.hbs b/ui/app/templates/components/fs/directory-entry.hbs index 9301dfebd95..9d671b1db4f 100644 --- a/ui/app/templates/components/fs/directory-entry.hbs +++ b/ui/app/templates/components/fs/directory-entry.hbs @@ -1,26 +1,14 @@ - {{#if task}} - {{#link-to "allocations.allocation.task.fs" task.allocation task pathToEntry activeClass="is-active"}} - {{#if entry.IsDir}} - {{x-icon "folder-outline"}} - {{else}} - {{x-icon "file-outline"}} - {{/if}} + {{#fs/link model=model path=pathToEntry}} + {{#if entry.IsDir}} + {{x-icon "folder-outline"}} + {{else}} + {{x-icon "file-outline"}} + {{/if}} - {{entry.Name}} - {{/link-to}} - {{else}} - {{#link-to "allocations.allocation.fs" allocation pathToEntry activeClass="is-active"}} - {{#if entry.IsDir}} - {{x-icon "folder-outline"}} - {{else}} - {{x-icon "file-outline"}} - {{/if}} - - {{entry.Name}} - {{/link-to}} - {{/if}} + {{entry.Name}} + {{/fs/link}} {{#unless entry.IsDir}}{{format-bytes entry.Size}}{{/unless}} {{moment-from entry.ModTime interval=1000}} diff --git a/ui/app/templates/components/fs/link.hbs b/ui/app/templates/components/fs/link.hbs new file mode 100644 index 00000000000..98c37a3609d --- /dev/null +++ b/ui/app/templates/components/fs/link.hbs @@ -0,0 +1,21 @@ +{{#if task}} + {{#if path}} + {{#link-to "allocations.allocation.task.fs" allocation task path activeClass="is-active"}} + {{yield}} + {{/link-to}} + {{else}} + {{#link-to "allocations.allocation.task.fs-root" allocation task activeClass="is-active"}} + {{yield}} + {{/link-to}} + {{/if}} +{{else}} + {{#if path}} + {{#link-to "allocations.allocation.fs" allocation path activeClass="is-active"}} + {{yield}} + {{/link-to}} + {{else}} + {{#link-to "allocations.allocation.fs-root" allocation activeClass="is-active"}} + {{yield}} + {{/link-to}} + {{/if}} +{{/if}} \ No newline at end of file From e9eb9248e0c27e5eec6561f6ea361ac4ff7d9d2f Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 10:30:51 -0500 Subject: [PATCH 22/32] Change message for inaccessible files --- ui/app/templates/components/task-file.hbs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/app/templates/components/task-file.hbs b/ui/app/templates/components/task-file.hbs index ecf9cae4ea3..83c6dcb5925 100644 --- a/ui/app/templates/components/task-file.hbs +++ b/ui/app/templates/components/task-file.hbs @@ -1,8 +1,7 @@ {{#if noConnection}}

      Cannot fetch file

      -

      The files for this task are inaccessible. Check the condition of the client the allocation is on.

      - +

      The files for this {{if task 'task' 'allocation'}} are inaccessible. Check the condition of the client the allocation is on.

      {{/if}}
      From f4c5a8e76849784baa46597744b2db7481d3fe6f Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 10:40:30 -0500 Subject: [PATCH 23/32] Extract model determination to one place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There’s no need to have these calculations scattered everywhere. --- ui/app/components/fs/directory-entry.js | 3 ++- ui/app/components/fs/link.js | 17 ++--------------- ui/app/components/task-file.js | 17 ++--------------- ui/app/templates/components/fs/breadcrumbs.hbs | 4 ++-- ui/app/templates/components/fs/browser.hbs | 4 ++-- .../templates/components/fs/directory-entry.hbs | 2 +- ui/tests/integration/task-file-test.js | 10 ++-------- 7 files changed, 13 insertions(+), 44 deletions(-) diff --git a/ui/app/components/fs/directory-entry.js b/ui/app/components/fs/directory-entry.js index da9044c0a44..f021b159ee0 100644 --- a/ui/app/components/fs/directory-entry.js +++ b/ui/app/components/fs/directory-entry.js @@ -5,7 +5,8 @@ import { isEmpty } from '@ember/utils'; export default Component.extend({ tagName: '', - model: null, + allocation: null, + task: null, pathToEntry: computed('path', 'entry.Name', function() { const pathWithNoLeadingSlash = this.get('path').replace(/^\//, ''); diff --git a/ui/app/components/fs/link.js b/ui/app/components/fs/link.js index a48a9b49044..df666e6d892 100644 --- a/ui/app/components/fs/link.js +++ b/ui/app/components/fs/link.js @@ -4,19 +4,6 @@ import { computed } from '@ember/object'; export default Component.extend({ tagName: '', - model: null, - - allocation: computed('model', function() { - if (this.model && this.model.allocation) { - return this.model.allocation; - } else { - return this.model; - } - }), - - task: computed('model', function() { - if (this.model && this.model.allocation) { - return this.model; - } - }), + allocation: null, + task: null, }); diff --git a/ui/app/components/task-file.js b/ui/app/components/task-file.js index 5ff705793a7..438b8d62470 100644 --- a/ui/app/components/task-file.js +++ b/ui/app/components/task-file.js @@ -14,7 +14,8 @@ export default Component.extend({ 'data-test-file-viewer': true, - model: null, + allocation: null, + task: null, file: null, stat: null, // { Name, IsDir, Size, FileMode, ModTime, ContentType } @@ -29,20 +30,6 @@ export default Component.extend({ mode: 'head', - allocation: computed('model', function() { - if (this.model.allocation) { - return this.model.allocation; - } else { - return this.model; - } - }), - - task: computed('model', function() { - if (this.model.allocation) { - return this.model; - } - }), - fileComponent: computed('stat.ContentType', function() { const contentType = this.stat.ContentType || ''; diff --git a/ui/app/templates/components/fs/breadcrumbs.hbs b/ui/app/templates/components/fs/breadcrumbs.hbs index c2b27ef625a..d89192b6afd 100644 --- a/ui/app/templates/components/fs/breadcrumbs.hbs +++ b/ui/app/templates/components/fs/breadcrumbs.hbs @@ -1,12 +1,12 @@
      • - {{#fs/link model=(if task task allocation)}} + {{#fs/link allocation=allocation task=task}} {{if task task.name allocation.shortId}} {{/fs/link}}
      • {{#each breadcrumbs as |breadcrumb|}}
      • - {{#fs/link model=(if task task allocation) path=breadcrumb.path}} + {{#fs/link allocation=allocation task=task path=breadcrumb.path}} {{breadcrumb.name}} {{/fs/link}}
      • diff --git a/ui/app/templates/components/fs/browser.hbs b/ui/app/templates/components/fs/browser.hbs index 875dab49865..b02d92316bc 100644 --- a/ui/app/templates/components/fs/browser.hbs +++ b/ui/app/templates/components/fs/browser.hbs @@ -1,7 +1,7 @@
        {{#if model.isRunning}} {{#if isFile}} - {{#task-file model=model file=path stat=stat class="fs-explorer"}} + {{#task-file allocation=allocation task=task file=path stat=stat class="fs-explorer"}} {{fs/breadcrumbs allocation=allocation task=task path=path}} {{/task-file}} {{else}} @@ -21,7 +21,7 @@ {{#t.sort-by prop="ModTime" class="has-text-right"}}Last Modified{{/t.sort-by}} {{/t.head}} {{#t.body as |row|}} - {{fs/directory-entry path=path model=model entry=row.model}} + {{fs/directory-entry path=path allocation=allocation task=task entry=row.model}} {{/t.body}} {{/list-table}} {{else}} diff --git a/ui/app/templates/components/fs/directory-entry.hbs b/ui/app/templates/components/fs/directory-entry.hbs index 9d671b1db4f..2b33428d177 100644 --- a/ui/app/templates/components/fs/directory-entry.hbs +++ b/ui/app/templates/components/fs/directory-entry.hbs @@ -1,6 +1,6 @@ - {{#fs/link model=model path=pathToEntry}} + {{#fs/link allocation=allocation task=task path=pathToEntry}} {{#if entry.IsDir}} {{x-icon "folder-outline"}} {{else}} diff --git a/ui/tests/integration/task-file-test.js b/ui/tests/integration/task-file-test.js index fd556b4229b..47a89ade441 100644 --- a/ui/tests/integration/task-file-test.js +++ b/ui/tests/integration/task-file-test.js @@ -25,7 +25,7 @@ module('Integration | Component | task file', function(hooks) { }); const commonTemplate = hbs` - {{task-file model=task file=file stat=stat}} + {{task-file allocation=allocation task=task file=file stat=stat}} `; const fileStat = (type, size = 0) => ({ @@ -46,12 +46,6 @@ module('Integration | Component | task file', function(hooks) { }, task: { name: 'task-name', - allocation: { - id: 'alloc-1', - node: { - httpAddr: HOST, - }, - }, }, file: 'path/to/file', stat: { @@ -190,7 +184,7 @@ module('Integration | Component | task file', function(hooks) { this.setProperties(props); await render(hbs` - {{#task-file model=task file=file stat=stat}} + {{#task-file allocation=allocation task=task file=file stat=stat}}
        Yielded content
        {{/task-file}} `); From 411cbb067652091d10cdbee3cd833b7707cdf8cf Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 10:44:06 -0500 Subject: [PATCH 24/32] Remove unused import --- ui/app/components/fs/link.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/app/components/fs/link.js b/ui/app/components/fs/link.js index df666e6d892..a5460143ff1 100644 --- a/ui/app/components/fs/link.js +++ b/ui/app/components/fs/link.js @@ -1,5 +1,4 @@ import Component from '@ember/component'; -import { computed } from '@ember/object'; export default Component.extend({ tagName: '', From 91bf69989deec07272b2102fbe65288a8102df12 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 10:44:21 -0500 Subject: [PATCH 25/32] Change browser invocation to be multi-line --- ui/app/templates/allocations/allocation/fs.hbs | 9 ++++++++- ui/app/templates/allocations/allocation/task/fs.hbs | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ui/app/templates/allocations/allocation/fs.hbs b/ui/app/templates/allocations/allocation/fs.hbs index 6c4c7b9541f..432e84dfbbd 100644 --- a/ui/app/templates/allocations/allocation/fs.hbs +++ b/ui/app/templates/allocations/allocation/fs.hbs @@ -1,3 +1,10 @@ {{title pathWithLeadingSlash " - Allocation " allocation.shortId " filesystem"}} {{allocation-subnav allocation=allocation}} -{{fs/browser model=allocation path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} +{{fs/browser + model=allocation + path=path + stat=stat + isFile=isFile + directoryEntries=directoryEntries + sortProperty=sortProperty + sortDescending=sortDescending}} \ No newline at end of file diff --git a/ui/app/templates/allocations/allocation/task/fs.hbs b/ui/app/templates/allocations/allocation/task/fs.hbs index d6b10f19b04..b76b92b69ce 100644 --- a/ui/app/templates/allocations/allocation/task/fs.hbs +++ b/ui/app/templates/allocations/allocation/task/fs.hbs @@ -1,3 +1,10 @@ {{title pathWithLeadingSlash " - Task " task.name " filesystem"}} {{task-subnav task=task}} -{{fs/browser model=task path=path stat=stat isFile=isFile directoryEntries=directoryEntries sortProperty=sortProperty sortDescending=sortDescending}} \ No newline at end of file +{{fs/browser + model=task + path=path + stat=stat + isFile=isFile + directoryEntries=directoryEntries + sortProperty=sortProperty + sortDescending=sortDescending}} \ No newline at end of file From 6b0667f509d1aebcdfc0d60d2a98d1506766904a Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 11:11:26 -0500 Subject: [PATCH 26/32] Move file component into fs directory --- ui/app/components/{task-file.js => fs/file.js} | 0 ui/app/templates/components/fs/browser.hbs | 4 ++-- .../components/{task-file.hbs => fs/file.hbs} | 0 .../integration/{task-file-test.js => fs/file-test.js} | 10 +++++----- 4 files changed, 7 insertions(+), 7 deletions(-) rename ui/app/components/{task-file.js => fs/file.js} (100%) rename ui/app/templates/components/{task-file.hbs => fs/file.hbs} (100%) rename ui/tests/integration/{task-file-test.js => fs/file-test.js} (96%) diff --git a/ui/app/components/task-file.js b/ui/app/components/fs/file.js similarity index 100% rename from ui/app/components/task-file.js rename to ui/app/components/fs/file.js diff --git a/ui/app/templates/components/fs/browser.hbs b/ui/app/templates/components/fs/browser.hbs index b02d92316bc..147d28bd7a0 100644 --- a/ui/app/templates/components/fs/browser.hbs +++ b/ui/app/templates/components/fs/browser.hbs @@ -1,9 +1,9 @@
        {{#if model.isRunning}} {{#if isFile}} - {{#task-file allocation=allocation task=task file=path stat=stat class="fs-explorer"}} + {{#fs/file allocation=allocation task=task file=path stat=stat class="fs-explorer"}} {{fs/breadcrumbs allocation=allocation task=task path=path}} - {{/task-file}} + {{/fs/file}} {{else}}
        diff --git a/ui/app/templates/components/task-file.hbs b/ui/app/templates/components/fs/file.hbs similarity index 100% rename from ui/app/templates/components/task-file.hbs rename to ui/app/templates/components/fs/file.hbs diff --git a/ui/tests/integration/task-file-test.js b/ui/tests/integration/fs/file-test.js similarity index 96% rename from ui/tests/integration/task-file-test.js rename to ui/tests/integration/fs/file-test.js index 47a89ade441..52ab9fd2129 100644 --- a/ui/tests/integration/task-file-test.js +++ b/ui/tests/integration/fs/file-test.js @@ -3,12 +3,12 @@ import { setupRenderingTest } from 'ember-qunit'; import { find, render, settled } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import Pretender from 'pretender'; -import { logEncode } from '../../mirage/data/logs'; +import { logEncode } from '../../../mirage/data/logs'; const { assign } = Object; const HOST = '1.1.1.1:1111'; -module('Integration | Component | task file', function(hooks) { +module('Integration | Component | fs/file', function(hooks) { setupRenderingTest(hooks); hooks.beforeEach(function() { @@ -25,7 +25,7 @@ module('Integration | Component | task file', function(hooks) { }); const commonTemplate = hbs` - {{task-file allocation=allocation task=task file=file stat=stat}} + {{fs/file allocation=allocation task=task file=file stat=stat}} `; const fileStat = (type, size = 0) => ({ @@ -184,9 +184,9 @@ module('Integration | Component | task file', function(hooks) { this.setProperties(props); await render(hbs` - {{#task-file allocation=allocation task=task file=file stat=stat}} + {{#fs/file allocation=allocation task=task file=file stat=stat}}
        Yielded content
        - {{/task-file}} + {{/fs/file}} `); assert.ok( From 8d688b2be838534f26b480fd7990ca4f59be092f Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 11:19:11 -0500 Subject: [PATCH 27/32] Remove task state adapter It makes more sense to concentrate these functions in the allocation adapter. --- ui/app/adapters/task-state.js | 39 ------------------- ui/app/models/task-state.js | 8 ---- .../routes/allocations/allocation/task/fs.js | 5 ++- 3 files changed, 3 insertions(+), 49 deletions(-) delete mode 100644 ui/app/adapters/task-state.js diff --git a/ui/app/adapters/task-state.js b/ui/app/adapters/task-state.js deleted file mode 100644 index f9f98ca6271..00000000000 --- a/ui/app/adapters/task-state.js +++ /dev/null @@ -1,39 +0,0 @@ -import ApplicationAdapter from './application'; -import { inject as service } from '@ember/service'; - -export default ApplicationAdapter.extend({ - token: service(), - - ls(model, path) { - return this.token - .authorizedRequest(`/v1/client/fs/ls/${model.allocation.id}?path=${encodeURIComponent(path)}`) - .then(handleFSResponse); - }, - - stat(model, path) { - return this.token - .authorizedRequest( - `/v1/client/fs/stat/${model.allocation.id}?path=${encodeURIComponent(path)}` - ) - .then(handleFSResponse); - }, -}); - -async function handleFSResponse(response) { - if (response.ok) { - return response.json(); - } else { - const body = await response.text(); - - // TODO update this if/when endpoint returns 404 as expected - const statusIs500 = response.status === 500; - const bodyIncludes404Text = body.includes('no such file or directory'); - - const translatedCode = statusIs500 && bodyIncludes404Text ? 404 : response.status; - - throw { - code: translatedCode, - toString: () => body, - }; - } -} diff --git a/ui/app/models/task-state.js b/ui/app/models/task-state.js index e6afba7e862..fb9736ab7e4 100644 --- a/ui/app/models/task-state.js +++ b/ui/app/models/task-state.js @@ -51,12 +51,4 @@ export default Fragment.extend({ restart() { return this.allocation.restart(this.name); }, - - ls(path) { - return this.store.adapterFor('task-state').ls(this, path); - }, - - stat(path) { - return this.store.adapterFor('task-state').stat(this, path); - }, }); diff --git a/ui/app/routes/allocations/allocation/task/fs.js b/ui/app/routes/allocations/allocation/task/fs.js index 097ba686a4d..7627a8d61c2 100644 --- a/ui/app/routes/allocations/allocation/task/fs.js +++ b/ui/app/routes/allocations/allocation/task/fs.js @@ -6,6 +6,7 @@ export default Route.extend({ model({ path = '/' }) { const decodedPath = decodeURIComponent(path); const task = this.modelFor('allocations.allocation.task'); + const allocation = task.allocation; const pathWithTaskName = `${task.name}${decodedPath.startsWith('/') ? '' : '/'}${decodedPath}`; @@ -16,13 +17,13 @@ export default Route.extend({ }; } - return RSVP.all([task.stat(pathWithTaskName), task.get('allocation.node')]) + return RSVP.all([allocation.stat(pathWithTaskName), task.get('allocation.node')]) .then(([statJson]) => { if (statJson.IsDir) { return RSVP.hash({ path: decodedPath, task, - directoryEntries: task.ls(pathWithTaskName).catch(notifyError(this)), + directoryEntries: allocation.ls(pathWithTaskName).catch(notifyError(this)), isFile: false, }); } else { From b3a620a7e5253506a4a03061ed75658f9358c15c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 11:29:08 -0500 Subject: [PATCH 28/32] Move FS page object up a level --- ui/tests/acceptance/allocation-fs-test.js | 2 +- ui/tests/acceptance/behaviors/fs.js | 2 +- ui/tests/acceptance/task-fs-test.js | 2 +- ui/tests/pages/allocations/{task => }/fs.js | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename ui/tests/pages/allocations/{task => }/fs.js (100%) diff --git a/ui/tests/acceptance/allocation-fs-test.js b/ui/tests/acceptance/allocation-fs-test.js index d1afc8ac0c4..a14fb1fdffa 100644 --- a/ui/tests/acceptance/allocation-fs-test.js +++ b/ui/tests/acceptance/allocation-fs-test.js @@ -6,7 +6,7 @@ import Response from 'ember-cli-mirage/response'; import browseFilesystem from './behaviors/fs'; -import FS from 'nomad-ui/tests/pages/allocations/task/fs'; +import FS from 'nomad-ui/tests/pages/allocations/fs'; let allocation; let files; diff --git a/ui/tests/acceptance/behaviors/fs.js b/ui/tests/acceptance/behaviors/fs.js index 47f2b07e245..b0e0f28d568 100644 --- a/ui/tests/acceptance/behaviors/fs.js +++ b/ui/tests/acceptance/behaviors/fs.js @@ -1,6 +1,6 @@ import { test } from 'qunit'; import { currentURL, visit } from '@ember/test-helpers'; -import FS from 'nomad-ui/tests/pages/allocations/task/fs'; +import FS from 'nomad-ui/tests/pages/allocations/fs'; import moment from 'moment'; import { filesForPath } from 'nomad-ui/mirage/config'; import Response from 'ember-cli-mirage/response'; diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index 3f3194db59c..0e08b914108 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -6,7 +6,7 @@ import Response from 'ember-cli-mirage/response'; import browseFilesystem from './behaviors/fs'; -import FS from 'nomad-ui/tests/pages/allocations/task/fs'; +import FS from 'nomad-ui/tests/pages/allocations/fs'; let allocation; let task; diff --git a/ui/tests/pages/allocations/task/fs.js b/ui/tests/pages/allocations/fs.js similarity index 100% rename from ui/tests/pages/allocations/task/fs.js rename to ui/tests/pages/allocations/fs.js From 3bbc718c45b586e8bf7ed5bbdf57d29ca3f0f97c Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 11:31:21 -0500 Subject: [PATCH 29/32] Rename task page object visit functions --- ui/tests/acceptance/task-fs-test.js | 6 +++--- ui/tests/pages/allocations/fs.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/tests/acceptance/task-fs-test.js b/ui/tests/acceptance/task-fs-test.js index 0e08b914108..4604aa61c3a 100644 --- a/ui/tests/acceptance/task-fs-test.js +++ b/ui/tests/acceptance/task-fs-test.js @@ -69,7 +69,7 @@ module('Acceptance | task fs', function(hooks) { finishedAt: new Date(), }); - await FS.visit({ id: allocation.id, name: task.name }); + await FS.visitTask({ id: allocation.id, name: task.name }); assert.ok(FS.hasEmptyState, 'Non-running task has no files'); assert.ok( FS.emptyState.headline.includes('Task is not Running'), @@ -83,7 +83,7 @@ module('Acceptance | task fs', function(hooks) { getTitleComponent: ({task}) => `Task ${task.name} filesystem`, getBreadcrumbComponent: ({task}) => task.name, getFilesystemRoot: ({ task }) => task.name, - pageObjectVisitFunctionName: 'visit', - pageObjectVisitPathFunctionName: 'visitPath', + pageObjectVisitFunctionName: 'visitTask', + pageObjectVisitPathFunctionName: 'visitTaskPath', }); }); diff --git a/ui/tests/pages/allocations/fs.js b/ui/tests/pages/allocations/fs.js index e2a05545e30..d04edb62b07 100644 --- a/ui/tests/pages/allocations/fs.js +++ b/ui/tests/pages/allocations/fs.js @@ -10,8 +10,8 @@ import { } from 'ember-cli-page-object'; export default create({ - visit: visitable('/allocations/:id/:name/fs'), - visitPath: visitable('/allocations/:id/:name/fs/:path'), + visitTask: visitable('/allocations/:id/:name/fs'), + visitTaskPath: visitable('/allocations/:id/:name/fs/:path'), visitAllocation: visitable('/allocations/:id/fs'), visitAllocationPath: visitable('/allocations/:id/fs/:path'), From 018737c867f6a286a4401f8fc564b35fed31a48d Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 11:32:49 -0500 Subject: [PATCH 30/32] Change order of imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I’d LOVE for some Prettier-esque approach to this 😝 --- ui/tests/acceptance/behaviors/fs.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ui/tests/acceptance/behaviors/fs.js b/ui/tests/acceptance/behaviors/fs.js index b0e0f28d568..0d13c021f59 100644 --- a/ui/tests/acceptance/behaviors/fs.js +++ b/ui/tests/acceptance/behaviors/fs.js @@ -1,11 +1,14 @@ import { test } from 'qunit'; import { currentURL, visit } from '@ember/test-helpers'; -import FS from 'nomad-ui/tests/pages/allocations/fs'; -import moment from 'moment'; + import { filesForPath } from 'nomad-ui/mirage/config'; -import Response from 'ember-cli-mirage/response'; import { formatBytes } from 'nomad-ui/helpers/format-bytes'; +import Response from 'ember-cli-mirage/response'; +import moment from 'moment'; + +import FS from 'nomad-ui/tests/pages/allocations/fs'; + const fileSort = (prop, files) => { let dir = []; let file = []; From d2ba5314cc130df1490305286f0a64f38487a19d Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Thu, 28 May 2020 12:00:22 -0500 Subject: [PATCH 31/32] Change order of visit functions --- ui/tests/pages/allocations/fs.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/tests/pages/allocations/fs.js b/ui/tests/pages/allocations/fs.js index d04edb62b07..fbfc8f9a73b 100644 --- a/ui/tests/pages/allocations/fs.js +++ b/ui/tests/pages/allocations/fs.js @@ -10,12 +10,12 @@ import { } from 'ember-cli-page-object'; export default create({ - visitTask: visitable('/allocations/:id/:name/fs'), - visitTaskPath: visitable('/allocations/:id/:name/fs/:path'), - visitAllocation: visitable('/allocations/:id/fs'), visitAllocationPath: visitable('/allocations/:id/fs/:path'), + visitTask: visitable('/allocations/:id/:name/fs'), + visitTaskPath: visitable('/allocations/:id/:name/fs/:path'), + fileViewer: { scope: '[data-test-file-viewer]', }, From 5f82c18d9f0912e5e354669f0c7dd7f96e1b4c80 Mon Sep 17 00:00:00 2001 From: Buck Doyle Date: Mon, 1 Jun 2020 08:02:44 -0500 Subject: [PATCH 32/32] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 551f7d5ff55..b90cbedf807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ IMPROVEMENTS: * csi: Move volume claim releases out of evaluation workers [[GH-8021](https://github.com/hashicorp/nomad/issues/8021)] * csi: Added support for `VolumeContext` and `VolumeParameters` [[GH-7957](https://github.com/hashicorp/nomad/issues/7957)] * logging: Remove spurious error log on task shutdown [[GH-8028](https://github.com/hashicorp/nomad/issues/8028)] + * ui: Added filesystem browsing for allocations [[GH-5871](https://github.com/hashicorp/nomad/pull/7951)] BUG FIXES: