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

Show upload status in workspace detail view #210

Merged
merged 7 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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 package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"direct-vuex": "^0.10.4",
"lodash": "^4.17.21",
"material-design-icons-iconfont": "^5.0.1",
"multinet": "0.21.4",
"multinet": "0.21.5",
"papaparse": "^5.3.0",
"vue": "^2.6.10",
"vue-async-computed": "^3.8.2",
Expand Down
10 changes: 10 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SingleUserWorkspacePermissionSpec, UserSpec } from 'multinet';
import api from '@/api';
import oauthClient from '@/oauth';
import { RoleLevel } from '@/utils/permissions';
import { Upload } from '@/types';

Vue.use(Vuex);

Expand All @@ -21,6 +22,7 @@ export interface State {
currentWorkspace: WorkspaceState | null;
userInfo: UserSpec | null;
currentWorkspacePermission: SingleUserWorkspacePermissionSpec | null;
uploads: Upload[];
}

const {
Expand All @@ -35,6 +37,7 @@ const {
currentWorkspace: null,
userInfo: null,
currentWorkspacePermission: null,
uploads: [],
} as State,
getters: {
tables(state: State, getters): string[] {
Expand Down Expand Up @@ -100,6 +103,10 @@ const {
setPermissionInfo(state, permissionInfo: SingleUserWorkspacePermissionSpec | null) {
state.currentWorkspacePermission = permissionInfo;
},

setUploads(state, uploads: Upload[]) {
state.uploads = uploads;
},
},
actions: {
async fetchWorkspaces(context) {
Expand All @@ -118,6 +125,9 @@ const {
const nodeTables = tables.filter((table) => table.edge === false);
const edgeTables = tables.filter((table) => table.edge === true);

const uploads = await api.uploads(workspace);
commit.setUploads(uploads.results);

const permissionsInfo = await api.getCurrentUserWorkspacePermissions(workspace);
commit.setPermissionInfo(permissionsInfo);

Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ export interface NetworkFileType extends FileType{
export interface FileTypeTable {
[key: string]: FileType;
}

export interface Upload {
blob: string;
status: string;
data_type: string;
}
174 changes: 101 additions & 73 deletions src/views/WorkspaceDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,39 @@
<workspace-option-menu :workspace="workspace" />
</v-app-bar>

<v-layout
wrap
<v-row
v-for="upload in uploads"
:key="upload.id"
>
<v-flex
md6
px-5
py-3
<v-col
cols="12"
class="ma-0"
>
<v-alert
border="left"
color="blue"
type="info"
class="mb-0"
>
<v-row align="center">
<v-col class="grow">
Uploading: {{ upload.blob.substring(upload.blob.indexOf('/') + 1) }}
</v-col>
<v-col class="shrink">
<v-progress-circular
indeterminate
color="white"
size="26"
/>
</v-col>
</v-row>
</v-alert>
</v-col>
</v-row>
<v-row class="ma-0">
<v-col
cols="6"
class="px-5"
>
<v-card
color="transparent"
Expand All @@ -104,12 +130,11 @@
:loading="loading"
/>
</v-card>
</v-flex>
</v-col>

<v-flex
md6
px-5
py-3
<v-col
cols="6"
class="px-5"
>
<v-card
color="transparent"
Expand All @@ -122,14 +147,16 @@
:loading="loading"
/>
</v-card>
</v-flex>
</v-layout>
</v-col>
</v-row>
</v-main>
</v-container>
</template>

<script lang="ts">
import Vue, { PropType } from 'vue';
import {
defineComponent, ref, PropType, computed, watch,
} from '@vue/composition-api';

import api from '@/api';
import TablePanel from '@/components/TablePanel.vue';
Expand All @@ -143,107 +170,108 @@ const workspaceNameRules: Array<(x: string) => string|boolean> = [
(x: string) => !surroundingWhitespace.test(x) || 'Workspace name cannot begin or end with whitespace',
];

export default Vue.extend({
export default defineComponent({
name: 'WorkspaceDetail',

components: {
TablePanel,
NetworkPanel,
WorkspaceOptionMenu,
},

props: {
workspace: {
type: String as PropType<string>,
required: true,
},
},
data() {
return {
localWorkspace: null as string | null,
editing: false,
requestError: null as string | null,
loading: false,
};
},

computed: {
nodeTables: () => store.getters.nodeTables,
edgeTables: () => store.getters.edgeTables,
tables: () => store.getters.tables,
networks: () => store.getters.networks,
setup(props, ctx) {
const router = ctx.root.$router;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
nameErrorMessages(this: any): string[] {
const { requestError } = this;
const localWorkspace = ref<string | null>(null);
const editing = ref(false);
const requestError = ref<string | null>(null);
const loading = ref(false);

const nodeTables = computed(() => store.getters.nodeTables);
const edgeTables = computed(() => store.getters.edgeTables);
const tables = computed(() => store.getters.tables);
const networks = computed(() => store.getters.networks);
const uploads = computed(() => store.state.uploads.filter((upload) => upload.status !== 'FINISHED'));
const nameErrorMessages = computed(() => {
const errors = [
...workspaceNameRules.map((rule) => rule(this.localWorkspace as string)),
...workspaceNameRules.map((rule) => rule(localWorkspace.value as string)),
requestError,
];

return errors.filter((res): res is string => typeof res === 'string');
},
},

watch: {
workspace() {
this.update();
},
});

// eslint-disable-next-line @typescript-eslint/no-explicit-any
localWorkspace(this: any) {
// Once the user types, clears the error returned on sending the rename API call.
this.requestError = null;
},
},
created() {
this.update();
},
methods: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
cancelRename(this: any) {
this.requestError = null;
this.localWorkspace = this.workspace;
this.editing = false;
},
function cancelRename() {
requestError.value = null;
localWorkspace.value = props.workspace;
editing.value = false;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async renameWorkspace(this: any) {
if (this.nameErrorMessages.length) {
async function renameWorkspace() {
if (nameErrorMessages.value.length) {
return;
}

if (this.localWorkspace === this.workspace) {
this.editing = false;
if (localWorkspace.value === props.workspace) {
editing.value = false;
return;
}

if (this.localWorkspace !== null) {
if (localWorkspace.value !== null) {
try {
const { name } = await api.renameWorkspace(this.workspace, this.localWorkspace);
this.$router.push(`/workspaces/${name}`);
this.editing = false;
this.requestError = null;
const { name } = await api.renameWorkspace(props.workspace, localWorkspace.value);
router.push(`/workspaces/${name}`);
editing.value = false;
requestError.value = null;

store.dispatch.fetchWorkspaces();
} catch (err) {
if (err.response.status === 409) {
this.requestError = 'A workspace by that name already exists';
requestError.value = 'A workspace by that name already exists';
} else {
this.requestError = `${Object.values(err.response.data).flat()[0]}`;
requestError.value = `${Object.values(err.response.data).flat()[0]}`;
}
}
}
},
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async update(this: any) {
this.loading = true;
async function update(this: any) {
loading.value = true;

this.localWorkspace = this.workspace;
await store.dispatch.fetchWorkspace(this.workspace);
this.loading = false;
},
},
localWorkspace.value = props.workspace;
await store.dispatch.fetchWorkspace(props.workspace);
loading.value = false;
}

watch(() => props.workspace, () => update());
watch(localWorkspace, () => { requestError.value = null; });

update();

return {
editing,
loading,
networks,
nodeTables,
edgeTables,
tables,
cancelRename,
renameWorkspace,
nameErrorMessages,
localWorkspace,
uploads,
};
},
});
</script>

Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6162,10 +6162,10 @@ multimatch@^2.1.0:
arrify "^1.0.0"
minimatch "^3.0.0"

[email protected].4:
version "0.21.4"
resolved "https://registry.yarnpkg.com/multinet/-/multinet-0.21.4.tgz#9b9015fdeebd245800833db21b8f8e6d81aa351d"
integrity sha512-lYdj11yi5PJblDMg+T1fTih/2RMgIljYoWhpKElUNOdwPCHmc4Z1wFAd7Yo3nf1qKic2qlx0ac45XTcswnl05g==
[email protected].5:
version "0.21.5"
resolved "https://registry.yarnpkg.com/multinet/-/multinet-0.21.5.tgz#417253d5dd91682c1efc076296261894432daeba"
integrity sha512-K76wN//AF/0ueCSB4eL/7pcf8mfmDmaa5lM8V+LL6E1kkrf1ucjBeFVhSrqcQ0HrtACawOmk7DEz6XZ6W4Na7w==
dependencies:
axios "^0.21.1"
django-s3-file-field "^0.1.2"
Expand Down