Skip to content

Commit 4d1871a

Browse files
authored
Merge pull request #303 from multinet-app/network-builder
Improve the network builder UI, check on the status of networks that are building
2 parents d2d95c8 + 67844fb commit 4d1871a

7 files changed

Lines changed: 99 additions & 50 deletions

File tree

components.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ declare module 'vue' {
1414
DeleteTableDialog: typeof import('./src/components/DeleteTableDialog.vue')['default']
1515
DeleteWorkspaceDialog: typeof import('./src/components/DeleteWorkspaceDialog.vue')['default']
1616
DownloadDialog: typeof import('./src/components/DownloadDialog.vue')['default']
17-
NetworkCreationTool: typeof import('./src/components/NetworkCreationTool.vue')['default']
17+
NetworkBuilder: typeof import('./src/components/NetworkBuilder.vue')['default']
1818
NetworkPanel: typeof import('./src/components/NetworkPanel.vue')['default']
1919
PermissionsDialog: typeof import('./src/components/PermissionsDialog.vue')['default']
2020
RouterLink: typeof import('vue-router')['RouterLink']
@@ -61,7 +61,6 @@ declare module 'vue' {
6161
VOverlay: typeof import('vuetify/lib')['VOverlay']
6262
VProgressCircular: typeof import('vuetify/lib')['VProgressCircular']
6363
VProgressLinear: typeof import('vuetify/lib')['VProgressLinear']
64-
VResponsive: typeof import('vuetify/lib')['VResponsive']
6564
VRow: typeof import('vuetify/lib')['VRow']
6665
VScrollXTransition: typeof import('vuetify/lib')['VScrollXTransition']
6766
VSelect: typeof import('vuetify/lib')['VSelect']

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
"direct-vuex": "^0.10.4",
3030
"eslint-import-resolver-alias": "^1.1.2",
3131
"lodash": "^4.17.21",
32-
"multinet": "0.21.15",
32+
"multinet": "0.23.1",
3333
"multinet-components": "^0.0.4",
3434
"papaparse": "^5.3.0",
3535
"unplugin-vue-components": "^0.23.0",

src/components/CreateModifyDialog.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
</div>
3737
</v-card>
3838
<v-card v-else-if="dialogStep === 1">
39-
<NetworkCreationTool
39+
<NetworkBuilder
4040
v-if="firstChosen === 0"
4141
:workspace="workspace"
42-
@success="dialog = false"
42+
@success="() => { dialog = false; emit('success') }"
4343
@back="firstChosen = undefined; dialogStep -= 1"
4444
/>
4545
<TableNetworkUploadStepper
@@ -55,7 +55,7 @@
5555
<script setup lang="ts">
5656
import store from '@/store';
5757
import { computed, ref, watch } from 'vue';
58-
import NetworkCreationTool from './NetworkCreationTool.vue';
58+
import NetworkBuilder from './NetworkBuilder.vue';
5959
import TableNetworkUploadStepper from './TableNetworkUploadStepper.vue';
6060
6161
const props = defineProps<{
Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<v-divider />
2424

2525
<!-- Data tables -->
26-
<template v-if="tableSamples.length">
26+
<div>
2727
<v-row no-gutters>
2828
<v-col cols="2">
2929
<v-list class="px-4">
@@ -64,32 +64,34 @@
6464
</v-list>
6565
</v-col>
6666
<v-divider vertical />
67-
<v-col cols="10" class="px-4">
68-
<v-row
69-
no-gutters
70-
justify="start"
71-
>
67+
<v-col cols="10" class="px-4 mt-2">
68+
<v-row justify="start">
69+
<p v-if="visibleTableSamples.length === 0" class="pa-4 mt-2">
70+
{{ tableSamples.length > 0
71+
? 'Please select some tables on the left that you\'d like to include in your network.'
72+
: "You haven't uploaded any tables. This view only works when you have some tables uploaded. Return to the previous step to upload data tables."
73+
}}
74+
</p>
7275
<v-card
7376
v-for="sample in visibleTableSamples"
7477
:key="sample.table.name"
7578
raised
7679
outlined
77-
class="mt-4"
80+
class="mt-4 ma-2"
7881
>
79-
<v-card-title class="primary white--text">
82+
<v-card-title class="grey lighten-3">
8083
<v-row class="ma-0">
8184
{{ sample.table.name }}
8285
<v-spacer />
8386
<v-switch
84-
dark
8587
hide-details
8688
class="ma-0"
8789
:disabled="edgeTable !== undefined && edgeTable.table.name !== sample.table.name"
8890
:value="edgeTable !== undefined && edgeTable.table.name === sample.table.name"
8991
@change="setEdgeTable(sample.table, $event)"
9092
>
9193
<template #label>
92-
<span class="white--text">Edge Table</span>
94+
Edge Table
9395
</template>
9496
</v-switch>
9597
</v-row>
@@ -104,25 +106,24 @@
104106
disable-sort
105107
>
106108
<template #header="{ props: { headers } }">
107-
<thead dark>
109+
<thead>
108110
<tr>
109111
<th
110112
v-for="{ value: col } in headers"
111113
:key="`${sample.table.name}:${col}`"
112114
style="width: 1px; white-space: nowrap;"
115+
class="pt-2 pb-4 grey lighten-3"
113116
>
114117
<!-- Include/Exclude Column -->
115118
<v-icon
116119
v-if="!excludedMap[sample.table.name][col]"
117120
:disabled="checkboxDisabled(sample.table, col)"
118-
dark
119121
@click="excludedMap[sample.table.name][col] = true"
120122
>
121123
mdi-checkbox-marked
122124
</v-icon>
123125
<v-icon
124126
v-else
125-
dark
126127
:disabled="checkboxDisabled(sample.table, col)"
127128
@click="excludedMap[sample.table.name][col] = false"
128129
>
@@ -139,14 +140,15 @@
139140
@input="menuOpen = $event"
140141
>
141142
<template #activator="{ on }">
142-
<v-icon
143-
:color="linkColor(sample.table, col)"
144-
dark
145-
:class="{ 'disable-events': linkDisabled(sample.table) }"
146-
v-on="on"
147-
>
148-
mdi-link
149-
</v-icon>
143+
<v-btn icon>
144+
<v-icon
145+
:color="linkColor(sample.table, col)"
146+
:class="{ 'disable-events': linkDisabled(sample.table) }"
147+
v-on="on"
148+
>
149+
mdi-link
150+
</v-icon>
151+
</v-btn>
150152
</template>
151153
<v-card max-height="30vh">
152154
<!-- Edge Table -->
@@ -221,7 +223,6 @@
221223
<v-icon
222224
:color="linkColor(sample.table, col, true)"
223225
:class="{ 'disable-events': joinDisabled(sample.table, col) }"
224-
dark
225226
v-on="on"
226227
>
227228
mdi-call-merge
@@ -288,7 +289,7 @@
288289
</v-row>
289290
</v-col>
290291
</v-row>
291-
</template>
292+
</div>
292293
</v-card-text>
293294

294295
<v-card-actions class="px-4 py-3">
@@ -304,6 +305,7 @@
304305
id="create-table"
305306
color="primary"
306307
:disabled="!valid"
308+
:loading="networkCreating"
307309
@click="createNetwork"
308310
>
309311
Create
@@ -408,11 +410,11 @@ const inNetworkTables = computed(() => [
408410
targetTable.value?.joined?.table,
409411
]);
410412
411-
interface ExclusionMap {
412-
[key: string]: {
413-
[innerKey: string]: boolean
414-
}
415-
}
413+
interface ExclusionMap {
414+
[key: string]: {
415+
[innerKey: string]: boolean
416+
}
417+
}
416418
417419
// Remove any no longer visible links
418420
watch(tablesVisible, (visible) => {
@@ -603,7 +605,7 @@ async function init() {
603605
604606
const rows = res.data.results;
605607
const headers: DataTableHeader[] = rows.length > 0 ? Object.keys(rows[0])
606-
.filter((header) => !['_id', '_key', '_rev'].includes(header))
608+
.filter((header) => !['_id', '_rev'].includes(header))
607609
.map((header) => ({ text: header, value: header }))
608610
: [];
609611
@@ -619,7 +621,7 @@ async function init() {
619621
620622
// Store value in tableSamples
621623
tableSamples.value = sortedSamples;
622-
tablesVisible.value = reactive(sortedSamples.reduce((obj, cur) => ({ ...obj, [cur.table.name]: true }), {}));
624+
tablesVisible.value = reactive(sortedSamples.reduce((obj, cur) => ({ ...obj, [cur.table.name]: false }), {}));
623625
}
624626
625627
// Load table from workspace and store in tableSamples
@@ -812,7 +814,6 @@ function columnItemText(item: CSVRow, key: string) {
812814
return `${truncated}...`;
813815
}
814816
815-
/* eslint-disable prefer-destructuring */
816817
function linkColor(table: BaseTable, col: string, join = false) {
817818
// There's at most 5 links
818819
// Edge -> Source
@@ -874,14 +875,14 @@ function linkColor(table: BaseTable, col: string, join = false) {
874875
875876
return undefined;
876877
}
877-
/* eslint-enable prefer-destructuring */
878878
879879
// Denotes whether the dialog is in a submittable state
880880
const valid = computed(() => !!(
881881
objectNameIsValid(networkName.value)
882882
&& edgeTable.value?.table
883883
&& sourceTable.value
884884
&& targetTable.value
885+
&& !tableSamples.value.map((sample) => sample.table.name).includes(networkName.value)
885886
));
886887
887888
const networkCreating = ref(false);
@@ -932,11 +933,6 @@ async function createNetwork() {
932933
</script>
933934

934935
<style scoped>
935-
.upload-preview table th, .table-title {
936-
background-color: #1976d2 !important;
937-
color: #fff !important;
938-
}
939-
940936
.disable-events {
941937
pointer-events: none
942938
}

src/utils/files.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ function generateColumnTypes(sampleRows: Record<string, unknown>[]) {
5555
const uniqueValuesInSample = new Set(valuesInSample);
5656

5757
const isKey = field === '_key' || field === 'id';
58-
const isSource = field === '_from' || field === 'source';
59-
const isTarget = field === '_to' || field === 'target';
58+
const isSource = (field === '_from' || field === 'source') && valuesInSample.every((value) => value.split('/').length === 2);
59+
const isTarget = (field === '_to' || field === 'target') && valuesInSample.every((value) => value.split('/').length === 2);
6060
const isLabel = field.toLocaleLowerCase().includes('name') || field === 'label';
6161
const boolean = isBoolean(uniqueValuesInSample);
6262
const category = uniqueValuesInSample.size <= 10 && !(uniqueValuesInSample.size === sampleRows.length);

src/views/WorkspaceDetail.vue

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@
8080
/>
8181
<v-spacer />
8282

83-
<create-modify-dialog :workspace="workspace" @success="startCheckingUpload" />
83+
<create-modify-dialog :workspace="workspace" @success="startChecking" />
8484
<workspace-option-menu :workspace="workspace" />
8585
</v-app-bar>
8686

87+
<!-- Display upload status -->
8788
<v-row
8889
v-for="upload in uploads"
8990
:key="upload.id"
@@ -124,6 +125,28 @@
124125
</v-col>
125126
</v-row>
126127

128+
<!-- Display network building status -->
129+
<v-alert
130+
v-if="networkBuildRequests.length > 0"
131+
border="left"
132+
color="blue"
133+
type="info"
134+
class="mb-0"
135+
>
136+
<v-row align="center">
137+
<v-col class="grow">
138+
Your network is being built
139+
</v-col>
140+
<v-col class="shrink">
141+
<v-progress-circular
142+
indeterminate
143+
color="white"
144+
size="26"
145+
/>
146+
</v-col>
147+
</v-row>
148+
</v-alert>
149+
127150
<session-panel :apps="apps" :workspace="workspace" :loading="loading" />
128151

129152
<v-row class="ma-0">
@@ -262,6 +285,30 @@ async function update(this: any) {
262285
watch(() => props.workspace, () => update());
263286
watch(localWorkspace, () => { requestError.value = null; });
264287
288+
const networkBuildRequests = ref<number[]>([]);
289+
async function checkNetworkBuilds() {
290+
networkBuildRequests.value = await api.networkBuildRequests(props.workspace);
291+
292+
if (networkBuildRequests.value.length === 0) {
293+
update();
294+
return true;
295+
}
296+
return false;
297+
}
298+
299+
async function startCheckingNetworkBuilds() {
300+
let timeout = 30 * 1000;
301+
const interval = 3 * 1000;
302+
303+
const checkUploadInterval = setInterval(async () => {
304+
if ((await checkNetworkBuilds()) || timeout <= 0) {
305+
clearInterval(checkUploadInterval);
306+
}
307+
308+
timeout -= interval;
309+
}, interval);
310+
}
311+
265312
async function checkUpload(upload: { id: number }) {
266313
const newUploadStatus = await api.uploads(props.workspace);
267314
store.commit.setUploads(newUploadStatus.results);
@@ -291,6 +338,13 @@ async function startCheckingUpload(upload: { id: number }) {
291338
}, interval);
292339
}
293340
341+
function startChecking(upload: { id: number } | undefined) {
342+
if (upload !== undefined) {
343+
startCheckingUpload(upload);
344+
}
345+
startCheckingNetworkBuilds();
346+
}
347+
294348
update();
295349
</script>
296350

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4196,10 +4196,10 @@ multinet-components@^0.0.4:
41964196
resolved "https://registry.yarnpkg.com/multinet-components/-/multinet-components-0.0.4.tgz#26c519733ce72145f5ebf81de1333b294903ee4b"
41974197
integrity sha512-T3r/UsB4r4OLZXFx8uIbgYKls1CQ2q8yerySCWQHEbJ0Jga57g2sIyHEpdecXo4Rf3yH/9ZcvhAqBIrV1hnF6A==
41984198

4199-
multinet@0.21.15:
4200-
version "0.21.15"
4201-
resolved "https://registry.yarnpkg.com/multinet/-/multinet-0.21.15.tgz#90d10eda63a646a9af972ce24c5b67d5f23278dd"
4202-
integrity sha512-UW+m3I61JvGTQf3YrmJRWXARcLMWInKXpjmXfhqeRwmqu8fwFIy+duLkF/jJb3qGxMKUWshEb72EP8JBAxX4uw==
4199+
multinet@0.23.1:
4200+
version "0.23.1"
4201+
resolved "https://registry.yarnpkg.com/multinet/-/multinet-0.23.1.tgz#6ee659f996bf1c1ad32d2a6ed63937c6f9e123dc"
4202+
integrity sha512-iyDGqKGMK5ZK1QiQPzku14mPkI7JQfHtytMlfwxs3tU0RnDaH+5GH+698Q5Hcnl7ONAF8ognLey1W3aTxseiHQ==
42034203
dependencies:
42044204
axios "^0.21.1"
42054205
django-s3-file-field "^0.1.2"

0 commit comments

Comments
 (0)