IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
Browse Source

Started implementing properties editors - WBCollectionFields for starters.

pull/1/head
parent
commit
c63bd07c37
6 changed files with 131 additions and 39 deletions
  1. +4
    -0
      frontend/src/css/index.css
  2. +16
    -0
      frontend/src/js/arvados/base/wb-update-field.js
  3. +40
    -31
      frontend/src/js/component/wb-collection-fields.js
  4. +60
    -0
      frontend/src/js/component/wb-json-editor.js
  5. +4
    -2
      frontend/src/js/widget/wb-accordion.js
  6. +7
    -6
      frontend/src/js/widget/wb-dialog.js

+ 4
- 0
frontend/src/css/index.css View File

@@ -21,3 +21,7 @@ div.wb-json-viewer {
font-family: "Courier New", fixed-width;
white-space: pre-wrap;
}
textarea.wb-json-editor {
font-family: "Courier New", fixed-width;
}

+ 16
- 0
frontend/src/js/arvados/base/wb-update-field.js View File

@@ -0,0 +1,16 @@
import makeArvadosRequest from 'make-arvados-request';
import arvadosTypeName from 'arvados-type-name';
function wbUpdateField(arvHost, arvToken, uuid, fieldName, fieldValue) {
const typeName = arvadosTypeName(uuid);
const data = {};
data[fieldName] = fieldValue;
const prom = makeArvadosRequest(arvHost, arvToken,
'/arvados/v1/' + typeName + 's/' + uuid, {
method: 'PUT',
data: JSON.stringify(data)
});
return prom;
}
export default wbUpdateField;

+ 40
- 31
frontend/src/js/component/wb-collection-fields.js View File

@@ -9,18 +9,54 @@ import WBNameAndUuid from 'wb-name-and-uuid';
import WBAccordion from 'wb-accordion';
import wbFormatSpecialValue from 'wb-format-special-value';
import WBJsonViewer from 'wb-json-viewer';
import WBJsonEditor from 'wb-json-editor';
import wbUpdateField from 'wb-update-field';
class WBCollectionFields extends Component {
componentDidMount() {
this.prepareRows();
this.fetchData();
}
componentWillReceiveProps(nextProps) {
this.props = nextProps;
this.prepareRows();
this.fetchData();
}
prepareRows() {
prepareRows(item) {
const { app } = this.props;
const { arvHost, arvToken } = app.state;
let rows = [
[ 'Name', item.name ],
[ 'Description', wbFormatSpecialValue(item.description) ],
[ 'Properties', (
<WBJsonEditor name="Properties" app={ app } value={ item.properties }
onChange={ value => wbUpdateField(arvHost, arvToken, item.uuid, 'properties', value)
.then(() => { item.properties = value; this.prepareRows(item); }) } />
) ],
[ 'Portable Data Hash', item.portable_data_hash ],
[ 'Replication Desired', item.replication_desired ? item.replication_desired : (
<i>{ String(item.replication_desired) }</i>
) ],
[ 'Replication Confirmed', item.replication_confirmed ? item.replication_confirmed : (
<i>{ String(item.replication_confirmed) }</i>
) ],
[ 'Replication Confirmed At', wbFormatDate(item.replication_confirmed_at) ],
[ 'Trash At', wbFormatDate(item.trash_at) ],
[ 'Delete At', wbFormatDate(item.delete_at) ],
[ 'Is Trashed', String(item.is_trashed) ],
[ 'Current Version UUID', (
<WBNameAndUuid app={ app } uuid={ item.current_version_uuid } />
) ],
[ 'Version', item.version ],
[ 'Preserve Version', String(item.preserve_version) ],
[ 'File Count', item.file_count ],
[ 'Total Size', filesize(item.file_size_total) ]
];
this.setState({ 'rows': rows });
}
fetchData() {
let { uuid, app } = this.props;
let { arvHost, arvToken } = app.state;
@@ -35,34 +71,7 @@ class WBCollectionFields extends Component {
const item = xhr.response.items[0];
if (!item)
throw Error('Item not found');
let rows = [
[ 'Name', item.name ],
[ 'Description', wbFormatSpecialValue(item.description) ],
[ 'Properties', (
<WBAccordion names={ ['Properties'] } cardHeaderClass="card-header-sm">
<WBJsonViewer app={ app } value={ item.properties } />
</WBAccordion>
) ],
[ 'Portable Data Hash', item.portable_data_hash ],
[ 'Replication Desired', item.replication_desired ? item.replication_desired : (
<i>{ String(item.replication_desired) }</i>
) ],
[ 'Replication Confirmed', item.replication_confirmed ? item.replication_confirmed : (
<i>{ String(item.replication_confirmed) }</i>
) ],
[ 'Replication Confirmed At', wbFormatDate(item.replication_confirmed_at) ],
[ 'Trash At', wbFormatDate(item.trash_at) ],
[ 'Delete At', wbFormatDate(item.delete_at) ],
[ 'Is Trashed', String(item.is_trashed) ],
[ 'Current Version UUID', (
<WBNameAndUuid app={ app } uuid={ item.current_version_uuid } />
) ],
[ 'Version', item.version ],
[ 'Preserve Version', String(item.preserve_version) ],
[ 'File Count', item.file_count ],
[ 'Total Size', filesize(item.file_size_total) ]
];
this.setState({ 'rows': rows });
this.prepareRows(item);
});
}


+ 60
- 0
frontend/src/js/component/wb-json-editor.js View File

@@ -0,0 +1,60 @@
import { h, Component, createRef } from 'preact';
import WBJsonViewer from 'wb-json-viewer';
import WBAccordion from 'wb-accordion';
import WBDialog from 'wb-dialog';
class WBJsonEditor extends Component {
constructor(...args) {
super(...args);
this.dialogRef = createRef();
}
render({ app, name, value, stringify, pretty, onChange }, { editValue, parseError }) {
return (
<div>
<WBDialog title={ 'Edit ' + name } ref={ this.dialogRef }
accept={ () => {
onChange(JSON.parse(editValue));
} }
canAccept={ () => {
try { JSON.parse(editValue) }
catch (exc) { this.setState({ parseError: exc.message }); return false; }
return true;
} }>
<div>
<textarea class="form-control wb-json-editor" value={ editValue } rows="10"
onChange={ e => this.setState({ editValue: e.target.value }) } />
{ parseError ? (
<div class="alert alert-danger" role="alert">
{ parseError }
</div>
) : null }
</div>
</WBDialog>
<WBAccordion names={ [ name ] } extraHeaderUi={ [ (
<button class="btn btn-link px-0" title="Edit"
onclick={ () => {
this.setState({ parseError: null,
editValue: stringify ?
pretty ? JSON.stringify(value, null, 2)
: JSON.stringify(value) : value });
this.dialogRef.current.show();
} }>
<i class="fas fa-edit text-secondary" />
</button>
) ] } cardHeaderClass="card-header-sm">
<WBJsonViewer app={ app } value={ value } stringify={ stringify }
pretty={ pretty } />
</WBAccordion>
</div>
);
}
}
WBJsonEditor.defaultProps = {
stringify: true,
pretty: true,
onChange: () => {}
};
export default WBJsonEditor;

+ 4
- 2
frontend/src/js/widget/wb-accordion.js View File

@@ -39,7 +39,7 @@ class WBAccordion extends Component {
this.setState({ ariaExpanded, collapseClass, buttonClass });
}
render({ children, names, cardHeaderClass }, { domId, headerDomIds,
render({ children, names, extraHeaderUi, cardHeaderClass }, { domId, headerDomIds,
collapseDomIds, collapseClass, ariaExpanded, buttonClass }) {
return (
@@ -53,6 +53,7 @@ class WBAccordion extends Component {
onclick={ () => this.toggle(i) }>
{ names[i] }
</button>
{ extraHeaderUi[i] }
</h2>
</div>
@@ -70,7 +71,8 @@ class WBAccordion extends Component {
};
WBAccordion.defaultProps = {
'cardHeaderClass': 'card-header'
cardHeaderClass: 'card-header',
extraHeaderUi: []
};
export default WBAccordion;

+ 7
- 6
frontend/src/js/widget/wb-dialog.js View File

@@ -18,7 +18,7 @@ class WBDialog extends Component {
$(this.modalRef.current).modal('hide');
}
render({ title, children, accept, reject }) {
render({ title, children, canAccept, accept, reject }) {
return (
<form class="m-0">
<div class="modal" tabindex="-1" role="dialog" ref={ this.modalRef }>
@@ -38,12 +38,12 @@ class WBDialog extends Component {
<div class="modal-footer">
{ children[1] ? children[1] : [
<input type="submit" class="btn btn-primary" value="Accept"
onclick={ e => { e.preventDefault(); this.hide(); accept(); } } />,
onclick={ e => { e.preventDefault(); if (!canAccept()) return; this.hide(); accept(); } } />,
<button type="button" class="btn btn-secondary"
onclick={ () => { this.hide(); reject(); } }>Cancel</button>
] }
</div>
</div>
</div>
</div>
@@ -53,9 +53,10 @@ class WBDialog extends Component {
}
WBDialog.defaultProps = {
'title': 'Dialog',
'accept': () => {},
'reject': () => {}
title: 'Dialog',
accept: () => {},
reject: () => {},
canAccept: () => true
};
export default WBDialog;

Loading…
Cancel
Save