Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Add allocation directory rendering #5873

Merged
merged 104 commits into from
Jul 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
6f984ac
Remove multi-path test for now
backspace Jun 21, 2019
274d1d6
Add rudimentary directory listing
backspace Jun 21, 2019
2796b07
Add placeholder for file/directory icons
backspace Jun 21, 2019
5f0e0a9
Replace placeholders with Structure icons
backspace Jun 21, 2019
875e09c
Change sorting to list directories first
backspace Jun 21, 2019
1d0c200
Convert list to table
backspace Jun 21, 2019
6025ede
Add entry sizes
backspace Jun 21, 2019
ca2baf3
Add tbody
backspace Jun 21, 2019
b8a5c42
Add file mode to table
backspace Jun 21, 2019
75edb48
Add hardcoded Mirage directory listing
backspace Jun 21, 2019
30e6771
Change files link to include path
backspace Jun 21, 2019
3726a6d
Add scenario for stable preview demonstration
backspace Jun 21, 2019
71c8c82
Add empty commit
backspace Jun 24, 2019
ad5621b
Add last modified column
backspace Jun 24, 2019
976cff0
Remove size from directory entries
backspace Jun 24, 2019
8eefd43
Remove file icon
backspace Jun 24, 2019
f1a4729
Add navigation into directories
backspace Jun 24, 2019
65635bc
Move directory endpoint into general Mirage config
backspace Jun 24, 2019
0856bb0
Add preliminary styling
backspace Jun 24, 2019
df5b49e
Remove file mode column
backspace Jun 24, 2019
abf4f94
Merge branch 'master' into f-ui/alloc-fs-directories
backspace Jun 24, 2019
acfed97
Add preliminary explorer breadcrumbs
backspace Jun 24, 2019
3eadd6d
Merge branch 'master' into f-ui/alloc-fs-directories
backspace Jun 24, 2019
4dae829
Add links to breadcrumb entries
backspace Jun 24, 2019
2a41ca6
Add active styling to final breadcrumb
backspace Jun 24, 2019
095ac6a
Add assertions on complete breadcrumbs text
backspace Jun 24, 2019
cc36fe5
Fix breadcrumb paths
backspace Jun 24, 2019
d89d5b7
Fix typo
backspace Jun 24, 2019
92266ee
Update test name
backspace Jun 24, 2019
04975f1
Add check for file vs directory
backspace Jun 24, 2019
999f57a
Restore skipped test
backspace Jun 24, 2019
02867c0
Change test name
backspace Jun 24, 2019
7a15b23
Add extensions to files in mock structure
backspace Jun 24, 2019
c59282e
Change example filenames to contain emoji
backspace Jun 24, 2019
e77f2eb
Add assertion about final filename breadcrumb
backspace Jun 24, 2019
53213a0
Add extension to nested file
backspace Jun 24, 2019
912f730
Rename page object property
backspace Jun 25, 2019
6ca3b5a
Add check for leading slash in path
backspace Jun 25, 2019
806b9bf
Remove temporary title
backspace Jun 25, 2019
dfba2b2
Add preliminary table styling
backspace Jun 25, 2019
c0fc9a4
Update file size heading
backspace Jun 25, 2019
9490c74
Add title for raw file modification datetime
backspace Jun 25, 2019
fc7baa7
Move breadcrumbs into table
backspace Jun 25, 2019
3d0f4e2
Updating styling of breadcrumbs
backspace Jun 25, 2019
d12df39
Add missing class name
backspace Jun 25, 2019
5593ae6
Add auto-updating to modification times
backspace Jun 25, 2019
0e8f569
Change to use less-redundant datetime formatter
backspace Jun 25, 2019
343a093
Add another example modification date
backspace Jun 25, 2019
16fcf9c
Restore file icon
backspace Jun 25, 2019
8c28f57
Add handling for empty directories
backspace Jun 26, 2019
3fafe68
Update Mirage scenario to work reliably
backspace Jun 26, 2019
df53346
Add modification times to all example files
backspace Jun 26, 2019
8fd85b5
Update routing so …/fs shows root directory
backspace Jun 26, 2019
c0d1cdd
Remove placeholder title
backspace Jun 26, 2019
65ddf93
Change fs retrieval to happen via token service
backspace Jun 26, 2019
dab54a6
Move fs API queries into adapter
backspace Jun 26, 2019
84a4b78
Rename property for directory listing
backspace Jun 26, 2019
4e91134
Change to consistently use double quotes
backspace Jun 26, 2019
f9a25d9
Extract directory entry component
backspace Jun 26, 2019
96200ba
Add line to turn off table-groups template lint
backspace Jun 26, 2019
d34433b
Fix indentation
backspace Jun 26, 2019
8d390f9
Change table container to not be full-width
backspace Jun 26, 2019
bdf681d
Convert task subnav partial to component
backspace Jun 26, 2019
19313e6
Change files link to be active at all levels
backspace Jun 26, 2019
3313a2e
Add prototype loading animation
backspace Jun 27, 2019
ac94741
Replace loading animation with Bulma .is-loading
backspace Jun 27, 2019
74fc0ce
Add loading animation for breadcrumb links
backspace Jun 27, 2019
0ca2353
Change width of name column
backspace Jun 27, 2019
d7232fa
Combine path tests into root FS file
backspace Jun 27, 2019
23623ec
Combine directory and file iterations
backspace Jun 27, 2019
6aae341
Remove doubled slashes in directory entry paths
backspace Jun 27, 2019
d0f6028
Remove doubled slashes from breadcrumb paths
backspace Jun 27, 2019
853add7
Add handling for fs/ API errors
backspace Jun 27, 2019
492e1d7
Merge branch 'f-ui/alloc-fs' into f-ui/alloc-fs-directories
backspace Jun 27, 2019
cc93a79
Rename breadcrumbs property
backspace Jun 27, 2019
4c13f15
Remove unused property
backspace Jun 27, 2019
da971d6
Refactor breadcrumbs computed property
backspace Jun 27, 2019
aa2c08d
Replace custom filter with isEmpty
backspace Jun 27, 2019
4e8e2f3
Remove unused dependent key
backspace Jun 27, 2019
6d53d05
Remove unused animation
backspace Jun 27, 2019
c601a27
Fix comment
backspace Jun 27, 2019
d6f71f2
Change to double quotes
backspace Jun 27, 2019
7c0b35c
Remove FIXME re Mirage fs endpoint
backspace Jun 27, 2019
48ce41f
Change test to use hardcoded task name
backspace Jun 27, 2019
07e8863
Correct import name
backspace Jun 28, 2019
2215038
Rename task property in controller
backspace Jun 28, 2019
4c845e8
Remove custom right-align class and use Bulma one
backspace Jun 28, 2019
ea6685d
Move FS table closer to tabs
backspace Jun 28, 2019
94de177
Remove unused properties
backspace Jun 28, 2019
95664ee
Reduce assertion complexity
backspace Jun 28, 2019
dbba6a2
Update comment about 404/500
backspace Jun 28, 2019
7793c85
Add externally-set controller property defaults
backspace Jul 2, 2019
51079cb
Rename component style file
backspace Jul 2, 2019
506d235
Remove unnecessary selector specificity
backspace Jul 2, 2019
a62308d
Move FS breadcrumbs styling inside component class
backspace Jul 2, 2019
f6421b4
Update style name for consistency
backspace Jul 2, 2019
e4da8bf
Change FS breadcrumbs dividers to grey
backspace Jul 2, 2019
09d88f3
Convert FS table head to boxed-section
backspace Jul 2, 2019
ae93227
Change to use x-icon
backspace Jul 2, 2019
437492b
Add Mirage handlers for other-host FS requests
backspace Jul 2, 2019
2d221bd
Add assertion explanations for double-slash
backspace Jul 2, 2019
d18ede9
Fix another double-slash issue
backspace Jul 2, 2019
24c25f6
Update entry hover with standard timestamp format
backspace Jul 2, 2019
ea4fd68
Add notifyError calls to route
backspace Jul 2, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions ui/app/adapters/task-state.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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=${path}`)
.then(handleFSResponse);
},

stat(model, path) {
return this.token
.authorizedRequest(`/v1/client/fs/stat/${model.allocation.id}?path=${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;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m awaiting feedback on whether 500-as-404 works similarly across platforms, so this may not be quite ready, but everything else is apart from the custom Mirage scenario that I can remove later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to a TODO as I think it’s fine to leave in for now and return to if the API changes.


throw {
code: translatedCode,
toString: () => body,
};
}
}
18 changes: 18 additions & 0 deletions ui/app/components/fs-directory-entry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { isEmpty } from '@ember/utils';

export default Component.extend({
tagName: '',

pathToEntry: computed('path', 'entry.Name', function() {
const pathWithNoLeadingSlash = this.get('path').replace(/^\//, '');
const name = this.get('entry.Name');

if (isEmpty(pathWithNoLeadingSlash)) {
return name;
} else {
return `${pathWithNoLeadingSlash}/${name}`;
}
}),
});
14 changes: 14 additions & 0 deletions ui/app/components/task-subnav.js
Original file line number Diff line number Diff line change
@@ -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.task.fs'),
fsRootIsActive: equal('router.currentRouteName', 'allocations.allocation.task.fs-root'),

filesLinkActive: or('fsIsActive', 'fsRootIsActive'),
});
3 changes: 3 additions & 0 deletions ui/app/controllers/allocations/allocation/task/fs-root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import FSController from './fs';

export default FSController.extend();
43 changes: 43 additions & 0 deletions ui/app/controllers/allocations/allocation/task/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { filterBy } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';

export default Controller.extend({
path: null,
task: null,
directoryEntries: null,
isFile: null,

directories: filterBy('directoryEntries', 'IsDir'),
files: filterBy('directoryEntries', 'IsDir', false),
backspace marked this conversation as resolved.
Show resolved Hide resolved

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;
}),
});
8 changes: 8 additions & 0 deletions ui/app/models/task-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,12 @@ 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);
},
});
5 changes: 2 additions & 3 deletions ui/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ Router.map(function() {
this.route('allocation', { path: '/:allocation_id' }, function() {
this.route('task', { path: '/:name' }, function() {
this.route('logs');
this.route('fs', function() {
this.route('path', { path: '/*path' });
});
this.route('fs-root', { path: '/fs' });
this.route('fs', { path: '/fs/*path' });
});
});
});
Expand Down
5 changes: 5 additions & 0 deletions ui/app/routes/allocations/allocation/task/fs-root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import FSRoute from './fs';

export default FSRoute.extend({
templateName: 'allocations/allocation/task/fs',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It personally trips me up when there is a route that has no template due to something like this, but I'm willing to try it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I don’t love it either 😐

});
37 changes: 37 additions & 0 deletions ui/app/routes/allocations/allocation/task/fs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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 task = this.modelFor('allocations.allocation.task');

const pathWithTaskName = `${task.name}${decodedPath.startsWith('/') ? '' : '/'}${decodedPath}`;

return task
.stat(pathWithTaskName)
.then(statJson => {
if (statJson.IsDir) {
return RSVP.hash({
path: decodedPath,
task,
directoryEntries: task.ls(pathWithTaskName).catch(notifyError(this)),
isFile: false,
});
} else {
return {
path: decodedPath,
task,
isFile: true,
};
}
})
.catch(notifyError(this));
},

setupController(controller, { path, task, directoryEntries, isFile } = {}) {
this._super(...arguments);
controller.setProperties({ path, task, directoryEntries, isFile });
},
});
15 changes: 0 additions & 15 deletions ui/app/routes/allocations/allocation/task/fs/path.js

This file was deleted.

1 change: 1 addition & 0 deletions ui/app/styles/components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@import './components/ember-power-select';
@import './components/empty-message';
@import './components/error-container';
@import './components/fs-explorer';
@import './components/gutter';
@import './components/gutter-toggle';
@import './components/inline-definitions';
Expand Down
73 changes: 73 additions & 0 deletions ui/app/styles/components/fs-explorer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.fs-explorer {
width: 100%;

.table.boxed-section-body.is-full-bleed {
border: 1px solid $grey-blue;
}

tbody {
a {
text-decoration: none;
color: inherit;

&:hover {
.name {
text-decoration: underline;
}
}
}
}

a {
position: relative;

// This is adapted from Bulma’s .button.is-loading::after
&.ember-transitioning-in::after {
animation: spinAround 500ms infinite linear;
border: 2px solid $grey-light;
border-radius: 290486px;
border-right-color: transparent;
border-top-color: transparent;
content: '';
display: block;
height: 1em;
width: 1em;
position: absolute;
right: -1.5em;
top: calc(50% - (1em / 2));
}
}

.breadcrumb {
margin: 0;

li::before {
color: $grey-light;
}

a {
padding-top: 0;
padding-bottom: 0;
color: $blue;
opacity: 1;
font-weight: $weight-bold;
text-decoration: none;

&:hover {
text-decoration: underline;
}

&.ember-transitioning-in {
margin-right: 1.5em;

&::after {
right: -1em;
}
}
}

.is-active a {
color: $black;
}
}
}
4 changes: 4 additions & 0 deletions ui/app/styles/core/tabs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@

+ * {
margin-top: 5em;

&.is-closer {
margin-top: calc(3.5em + 1px);
}
backspace marked this conversation as resolved.
Show resolved Hide resolved
}

@media #{$mq-hidden-gutter} {
Expand Down
66 changes: 65 additions & 1 deletion ui/app/templates/allocations/allocation/task/fs.hbs
Original file line number Diff line number Diff line change
@@ -1 +1,65 @@
{{outlet}}
{{task-subnav task=task}}
<section class="section is-closer">
{{#if task.isRunning}}
<div class="fs-explorer boxed-section">
<div class="boxed-section-head">
<nav class="breadcrumb" data-test-fs-breadcrumbs>
<ul>
<li class={{if breadcrumbs "" "is-active"}}>
{{#link-to "allocations.allocation.task.fs-root" task.allocation task activeClass="is-active"}}
{{task.name}}
{{/link-to}}
</li>
{{#each breadcrumbs as |breadcrumb|}}
<li class={{if breadcrumb.isLast "is-active"}}>
{{#link-to "allocations.allocation.task.fs" task.allocation task breadcrumb.path activeClass="is-active"}}
{{breadcrumb.name}}
{{/link-to}}
</li>
{{/each}}
</ul>
</nav>
</div>

{{#if isFile}}
<div class="boxed-section-body">
<div data-test-file-viewer>placeholder file viewer</div>
</div>
{{else}}
{{! template-lint-disable table-groups }}
<table class="table boxed-section-body is-full-bleed is-compact">
{{#if directoryEntries}}
<thead>
<tr>
<th class="is-two-thirds">Name</th>
<th class="has-text-right">File Size</th>
<th class="has-text-right">Last Modified</th>
</tr>
</thead>
<tbody>
{{#each (append directories files) as |entry|}}
{{fs-directory-entry path=path task=task entry=entry}}
{{/each}}
</tbody>
{{else}}
<tbody>
<tr data-test-entry>
<td colspan="3">
<span data-test-empty-icon>{{x-icon "alert-circle-outline"}}</span>
<span class="name" data-test-name>Directory is empty</span>
</td>
</tr>
</tbody>
{{/if}}
</table>
{{/if}}
</div>
{{else}}
<div data-test-not-running class="empty-message">
<h3 data-test-not-running-headline class="empty-message-headline">Task is not Running</h3>
<p data-test-not-running-body class="empty-message-body">
Cannot access files of a task that is not running.
</p>
</div>
{{/if}}
</section>
14 changes: 0 additions & 14 deletions ui/app/templates/allocations/allocation/task/fs/index.hbs

This file was deleted.

4 changes: 0 additions & 4 deletions ui/app/templates/allocations/allocation/task/fs/path.hbs

This file was deleted.

2 changes: 1 addition & 1 deletion ui/app/templates/allocations/allocation/task/index.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{partial "allocations/allocation/task/subnav"}}
{{task-subnav task=model}}
backspace marked this conversation as resolved.
Show resolved Hide resolved
<section class="section">
{{#if error}}
<div data-test-inline-error class="notification is-danger">
Expand Down
Loading