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 3 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
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;
}
168 changes: 95 additions & 73 deletions src/views/WorkspaceDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,28 @@
<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"
>
Uploading: {{ upload.blob.substring(upload.blob.indexOf('/') + 1) }}
</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 +119,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 +136,20 @@
: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 { useRouter } from 'vue-router'; // Router import vue3 syntax
// eslint-disable-next-line import/no-cycle
import router from '@/router'; // Temporary router syntax that lets us use the old push
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// import { useRouter } from 'vue-router'; // Router import vue3 syntax
// eslint-disable-next-line import/no-cycle
import router from '@/router'; // Temporary router syntax that lets us use the old push

If my suggestion around setup is committed, this is no longer needed.

Copy link
Member Author

Choose a reason for hiding this comment

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

See c141af6


import api from '@/api';
import TablePanel from '@/components/TablePanel.vue';
Expand All @@ -143,107 +163,109 @@ 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) {
// const router = useRouter();
Copy link
Member

Choose a reason for hiding this comment

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

This is how I use the router with CompositionAPI on Vue2

Suggested change
setup(props) {
// const router = useRouter();
setup(props, ctx) {
const router = ctx.root.$router;

Copy link
Member Author

Choose a reason for hiding this comment

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

See c141af6


// 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());
// eslint-disable-next-line no-return-assign
watch(localWorkspace, () => requestError.value = null);
Copy link
Member

Choose a reason for hiding this comment

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

Rather than ignore the rule, I'd just follow it here

Suggested change
// eslint-disable-next-line no-return-assign
watch(localWorkspace, () => requestError.value = null);
watch(localWorkspace, () => { requestError.value = null; });

Copy link
Member Author

Choose a reason for hiding this comment

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

See c141af6


update();

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

Expand Down