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

Bundle store details page #3860

Merged
merged 29 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
eeaccd7
fix error message
jzwang43 Sep 27, 2021
2f637a5
add bundle store cli commands
jzwang43 Oct 10, 2021
8488f1c
added store view
jzwang43 Oct 26, 2021
2fb660e
fix text
jzwang43 Oct 26, 2021
ce738f9
fix test
jzwang43 Oct 26, 2021
6be7cac
Update codalab/lib/bundle_cli.py
jzwang43 Dec 2, 2021
bcc516c
Remove replicate for now
jzwang43 Dec 2, 2021
4cd9231
Revert "fix error message"
jzwang43 Dec 2, 2021
dbcf8bd
Merge branch 'master' into bundle-store-cli
jzwang43 Dec 2, 2021
68ac1a3
Merge branch 'master' into bundle-store-cli
jzwang43 Dec 10, 2021
8e4eddc
Merge branch 'master' into bundle-details
jzwang43 Dec 10, 2021
33dfc3f
Merge branch 'master' of github.com:codalab/codalab-worksheets into b…
epicfaace Dec 12, 2021
9b1fff9
Fix endpoints to use bulk, add "cl store add" impl
epicfaace Dec 12, 2021
b0ca14d
refresh
epicfaace Dec 12, 2021
75f60b8
more impl for bundle store commands
epicfaace Dec 12, 2021
2c901f6
update
epicfaace Dec 12, 2021
7184cf2
fix
epicfaace Dec 12, 2021
04aaa4d
Add deletion, support deletion logic
epicfaace Dec 12, 2021
974ef31
Fix delete
epicfaace Dec 12, 2021
f864bb2
Support "cl upload --store"
epicfaace Dec 12, 2021
e7c629c
Merge branch 'master' into bundle-details
jzwang43 Dec 13, 2021
5a5f662
Merge branch 'master' into bundle-store-cli
epicfaace Dec 13, 2021
5957626
Update references
epicfaace Dec 13, 2021
d9f34cb
Merge branch 'bundle-store-cli' of github.com:codalab/codalab-workshe…
epicfaace Dec 13, 2021
8ff4d38
Merge branch 'bundle-store-cli' into bundle-details
jzwang43 Dec 13, 2021
5fee8ff
finishing up
jzwang43 Dec 13, 2021
3fddd17
Add name field
jzwang43 Dec 13, 2021
a61eb21
Merge branch 'master' into bundle-details
jzwang43 Dec 14, 2021
be6cd44
Update bundles.py
jzwang43 Dec 14, 2021
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
2 changes: 1 addition & 1 deletion codalab/model/bundle_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3040,7 +3040,7 @@ def get_bundle_store(self, user_id: int, uuid: str = None, name: str = None) ->
).fetchone()
return {
'uuid': row.uuid,
'owner': row.owner_id,
'owner_id': row.owner_id,
'name': row.name,
'storage_type': row.storage_type,
'storage_format': row.storage_format,
Expand Down
38 changes: 22 additions & 16 deletions codalab/rest/bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,22 +543,28 @@ def _add_bundle_store():
# updated_bundle_store = local.model.update_bundle_store(request.user.user_id, uuid, update)
# return BundleStoreSchema(many=True).dump(updated_bundle_store).data

# TODO: Endpoint not tested / used, reenable when we use it.
# @get('/bundle_stores/<uuid:re:%s>' % spec_util.UUID_STR, apply=AuthenticatedProtectedPlugin())
# def _fetch_bundle_store(uuid):
# """
# Fetch the bundle store corresponding to the specified uuid.

# Returns a single bundle store, with the following parameters:
# - `uuid`: bundle store UUID
# - `owner_id`: owner of bundle store
# - `name`: name of bundle store
# - `storage_type`: type of storage being used for bundle store (GCP, AWS, etc)
# - `storage_format`: the format in which storage is being stored (UNCOMPRESSED, COMPRESSED_V1, etc)
# - `url`: a self-referential URL that points to the bundle store.
# """
# bundle_store = local.model.get_bundle_store(request.user.user_id, uuid)
# return BundleStoreSchema(many=True).dump(bundle_store).data

@get('/bundle_stores/<uuid:re:%s>' % spec_util.UUID_STR, apply=AuthenticatedProtectedPlugin())
def _fetch_bundle_store(uuid):
"""
Fetch the bundle store corresponding to the specified uuid.

Returns a single bundle store, with the following parameters:
- `uuid`: bundle store UUID
- `owner_id`: owner of bundle store
- `name`: name of bundle store
- `storage_type`: type of storage being used for bundle store (GCP, AWS, etc)
- `storage_format`: the format in which storage is being stored (UNCOMPRESSED, COMPRESSED_V1, etc)
- `url`: a self-referential URL that points to the bundle store.
"""
bundle_store = local.model.get_bundle_store(request.user.user_id, uuid)
data = BundleStoreSchema().dump(bundle_store).data

# Fetch username instead of user_id for display on the front end.
data['data']['attributes']['owner'] = local.model.get_user(
user_id=data['data']['attributes']['owner']
).user_name
return data


@delete('/bundle_stores', apply=AuthenticatedProtectedPlugin())
Expand Down
12 changes: 12 additions & 0 deletions docs/REST-API-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,18 @@ JSON parameters:
- `authentication`: key for authentication that the bundle store uses.
Returns the data of the created bundle store.

### `GET /bundle_stores/<uuid:re:0x[0-9a-f]{32}>`

Fetch the bundle store corresponding to the specified uuid.

Returns a single bundle store, with the following parameters:
- `uuid`: bundle store UUID
- `owner_id`: owner of bundle store
- `name`: name of bundle store
- `storage_type`: type of storage being used for bundle store (GCP, AWS, etc)
- `storage_format`: the format in which storage is being stored (UNCOMPRESSED, COMPRESSED_V1, etc)
- `url`: a self-referential URL that points to the bundle store.

### `DELETE /bundle_stores`

Delete the specified bundle stores.
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/CodalabApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import NewDashboard from './components/Dashboard/NewDashboard';
// Routes
import HomePage from './routes/HomePage';
import BundleRoute from './routes/BundleRoute';
import StoreRoute from './routes/StoreRoute';

import history from './history';
import Cookies from 'universal-cookie';
Expand Down Expand Up @@ -119,6 +120,7 @@ function CodalabApp() {
path='/users'
render={(props) => <NewDashboard {...props} auth={fakeAuth} />}
/>
<Route path='/stores/:uuid' component={StoreRoute} />
<Route component={PageNotFound} />
</Switch>
{/*Footer.*/}
Expand Down
119 changes: 119 additions & 0 deletions frontend/src/components/Store/Store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// @flow
import * as React from 'react';
import SubHeader from '../SubHeader';
import ContentWrapper from '../ContentWrapper';
import { renderFormat } from '../../util/worksheet_utils';
import './Store.scss';
import ErrorMessage from '../worksheets/ErrorMessage';
import { fetchStores } from '../../util/apiWrapper';

class Store extends React.Component {
state = {
errorMessages: [],
storeInfo: null,
};
/**
* Fetch store data and update the state of this component.
*/
refreshStore = () => {
const { uuid } = this.props;
fetchStores(uuid)
.then((response) => {
const {
data: { attributes: storeInfo },
} = response;
console.log('storeInfo', storeInfo);

this.setState({
storeInfo,
});
})
.catch((err) => {
this.setState({ errorMessages: [err.toString()] });
});
};

componentDidMount = () => {
this.refreshStore();
};

/** Renderer. */
render = () => {
const storeInfo = this.state.storeInfo;
console.log('storeInfo', storeInfo);
if (!storeInfo) {
// Error
if (this.state.errorMessages.length > 0) {
return <ErrorMessage message={"Not found: '/stores/" + this.props.uuid + "'"} />;
}

// Still loading
return (
<div id='store-message' className='store-detail'>
<img alt='Loading' src={`${process.env.PUBLIC_URL}/img/Preloader_Small.gif`} />{' '}
Loading store info...
</div>
);
}

const storeMetadataChanged = this.refreshStore;

const content = (
<div id='panel_content'>
{renderErrorMessages(this.state.errorMessages)}
{renderHeader(storeInfo, storeMetadataChanged)}
</div>
);
return (
<div id='store-content'>
<React.Fragment>
<SubHeader title='Store View' />
<ContentWrapper>{content}</ContentWrapper>
</React.Fragment>
</div>
);
};
}

function renderErrorMessages(messages) {
return (
<div id='store-error-messages'>
{messages.map((message) => {
return <div className='alert alert-danger alert-dismissable'>{message}</div>;
})}
</div>
);
}

function createRow(key, value) {
return (
<tr key={key}>
<th>
<span>{key}</span>
</th>
<td>
<span>{value}</span>
</td>
</tr>
);
}

function renderHeader(storeInfo) {
// Display basic information.
let rows = [];
rows.push(createRow('name', storeInfo.name));
rows.push(createRow('uuid', storeInfo.uuid));
rows.push(createRow('bundle store type', storeInfo.storage_type));
rows.push(createRow('owner', storeInfo.owner === null ? '<anonymous>' : storeInfo.owner));
rows.push(createRow('location', storeInfo.url));

return (
<div>
<table className='store-meta table'>
<tbody>{rows.map((elem) => elem)}</tbody>
</table>
</div>
);
}

export default Store;
Loading