Skip to content

Commit 9adee5a

Browse files
authored
Merge pull request #4872 from akolson/revamp-content-file-mgt
Revamp content file mgt
2 parents 26005dc + f40bb0f commit 9adee5a

File tree

8 files changed

+217
-132
lines changed

8 files changed

+217
-132
lines changed

contentcuration/contentcuration/frontend/channelEdit/components/edit/EditModal.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,4 +675,8 @@
675675
margin-top: -4px !important;
676676
}
677677
678+
::v-deep .v-dialog__content {
679+
z-index: 5 !important;
680+
}
681+
678682
</style>

contentcuration/contentcuration/frontend/channelEdit/views/files/FileUpload.vue

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<div style="width: 100%;">
44
<VCard
5-
v-if="!primaryFileMapping.length"
5+
v-if="!primaryFileCount"
66
data-test="error"
77
flat
88
>
@@ -14,10 +14,32 @@
1414
</VCardText>
1515
</VCard>
1616
<VLayout v-else row wrap>
17-
<VFlex sm12 md6 lg5 xl4>
17+
<VFlex sm12 md12 lg12 xl12>
1818
<p>
1919
<ContentNodeIcon :kind="node.kind" includeText />
2020
</p>
21+
</VFlex>
22+
<VFlex sm12 md6 lg7 xl7 class="pr-4">
23+
<h3>
24+
{{ $tr('filesHeader') }}
25+
</h3>
26+
<VList threeLine>
27+
<FileUploadItem
28+
v-for="item in primaryFileMapping"
29+
:key="item.preset.id"
30+
:file="item.file"
31+
:preset="item.preset"
32+
:allowFileRemove="allowFileRemove"
33+
:uploadCompleteHandler="handleUploadComplete"
34+
@selected="selected = item.file.id"
35+
@remove="showRemoveFileWarning = primaryFileCount > 1"
36+
/>
37+
</VList>
38+
</VFlex>
39+
<VFlex sm12 md6 lg5 xl5>
40+
<h3 v-if="selectedFilename" class="mb-3">
41+
{{ selectedFilename }}
42+
</h3>
2143
<div class="preview-wrapper">
2244
<VCard v-if="!primaryFileCount" flat class="mb-2 message-card">
2345
<VLayout align-center justify-center fill-height>
@@ -39,32 +61,19 @@
3961
/>
4062
</div>
4163
</VFlex>
42-
<VFlex sm12 md6 lg7 xl8>
43-
<VContainer fluid>
44-
<VLayout alignStart>
45-
<VRadioGroup
46-
v-model="selected"
47-
hide-details
48-
:label="$tr('filesHeader')"
49-
class="subheading"
50-
>
51-
<VList threeLine>
52-
<FileUploadItem
53-
v-for="item in primaryFileMapping"
54-
:key="item.preset.id"
55-
:file="item.file"
56-
:preset="item.preset"
57-
:allowFileRemove="allowFileRemove"
58-
:uploadCompleteHandler="handleUploadComplete"
59-
@selected="selected = item.file.id"
60-
@remove="handleRemoveFile"
61-
/>
62-
</VList>
63-
</VRadioGroup>
64-
</VLayout>
65-
</VContainer>
66-
</VFlex>
6764
</VLayout>
65+
66+
<KModal
67+
v-if="showRemoveFileWarning"
68+
data-test="remove-file-warning"
69+
:title="$tr('removeFile')"
70+
:submitText="$tr('yesButton')"
71+
:cancelText="$tr('cancelButton')"
72+
@submit="handleRemoveFile"
73+
@cancel="showRemoveFileWarning = false"
74+
>
75+
<p>{{ $tr("removeFileDescription", { fileTypes: allowedFileTypes }) }}</p>
76+
</KModal>
6877
</div>
6978

7079
</template>
@@ -94,6 +103,7 @@
94103
data() {
95104
return {
96105
selected: null,
106+
showRemoveFileWarning: false,
97107
};
98108
},
99109
computed: {
@@ -118,22 +128,32 @@
118128
return this.fileCount > 1;
119129
},
120130
primaryFileCount() {
121-
return this.files.filter(file => !file.preset.supplementary).length;
131+
return this.primaryFileMapping.length;
122132
},
123133
primaryFileMapping() {
124134
return sortBy(
125135
this.presets
126-
.filter(p => !p.supplementary)
127136
.map(preset => {
128-
return {
129-
preset,
130-
order: preset.order,
131-
file: this.files.find(file => file.preset.id === preset.id),
132-
};
133-
}),
137+
const file = this.files.find(file => file.preset.id === preset.id);
138+
if (!preset.supplementary && file) {
139+
return { preset, order: preset.order, file };
140+
}
141+
return null;
142+
})
143+
.filter(item => item !== null),
134144
'order'
135145
);
136146
},
147+
selectedFilename() {
148+
const file = this.files.find(f => f.id === this.selected);
149+
return file ? file.original_filename : '';
150+
},
151+
allowedFileTypes() {
152+
return this.presets
153+
.filter(p => !p.supplementary && Array.isArray(p.allowed_formats))
154+
.map(p => p.allowed_formats.join(', '))
155+
.join(', ');
156+
},
137157
},
138158
watch: {
139159
'files.length'(newCount, oldCount) {
@@ -163,17 +183,25 @@
163183
eventLabel: 'Related file',
164184
});
165185
},
166-
handleRemoveFile(file) {
167-
this.deleteFile(file);
168-
if (file.id === this.selected) {
169-
this.selectFirstFile();
186+
handleRemoveFile() {
187+
const selectedFile = this.files.find(f => f.id === this.selected);
188+
if (selectedFile) {
189+
this.deleteFile(selectedFile).then(() => {
190+
this.selectFirstFile();
191+
});
170192
}
193+
this.showRemoveFileWarning = false;
171194
},
172195
},
173196
$trs: {
174-
filesHeader: 'Preview files',
197+
filesHeader: 'Files',
175198
fileError: 'Unsupported file type',
176199
noFileText: 'Missing files',
200+
removeFile: 'Remove file',
201+
removeFileDescription:
202+
'Once this file is removed, this resource will only be able to include a single file from the formats: { fileTypes }. Are you sure you want to continue?',
203+
yesButton: 'Yes',
204+
cancelButton: 'Cancel',
177205
},
178206
};
179207

contentcuration/contentcuration/frontend/channelEdit/views/files/FileUploadItem.vue

Lines changed: 87 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,19 @@
1111
<VListTile
1212
data-test="list-item"
1313
v-bind="$attrs"
14+
tabindex="0"
1415
@click.stop="file ? $emit('selected') : openFileDialog()"
1516
>
16-
<VListTileAction>
17-
<VRadio
18-
v-if="file"
19-
:key="file.id"
20-
:value="file.id"
21-
color="primary"
22-
data-test="radio"
23-
/>
24-
</VListTileAction>
2517
<VListTileContent>
2618
<VListTileSubTitle>{{ translateConstant(preset.id) }}</VListTileSubTitle>
27-
<VListTileTitle>
28-
<ActionLink
19+
<VListTileTitle class="file-display">
20+
<span
2921
v-if="fileDisplay"
3022
class="notranslate"
31-
:text="formattedFileDisplay"
32-
data-test="file-link"
33-
@click="openFileDialog"
34-
/>
23+
data-test="file-name"
24+
>
25+
{{ formattedFileDisplay }}
26+
</span>
3527
<ActionLink
3628
v-else
3729
data-test="upload-link"
@@ -53,15 +45,20 @@
5345
</VListTileContent>
5446
<VSpacer />
5547
<VListTileAction v-if="fileDisplay">
56-
<div v-if="allowFileRemove" class="remove-icon">
57-
<IconButton
58-
icon="clear"
59-
color="grey"
60-
:text="$tr('removeFileButton')"
61-
data-test="remove"
62-
@click="$emit('remove', file)"
63-
/>
64-
</div>
48+
<KIconButton
49+
size="small"
50+
icon="optionsHorizontal"
51+
appearance="flat-button"
52+
data-test="show-file-options"
53+
>
54+
<template #menu>
55+
<KDropdownMenu
56+
:options="previewFilesOptions"
57+
data-test="file-options"
58+
@select="(option) => option.onClick(openFileDialog)"
59+
/>
60+
</template>
61+
</KIconButton>
6562
</VListTileAction>
6663
</VListTile>
6764
</FileDropzone>
@@ -72,10 +69,9 @@
7269

7370
<script>
7471
75-
import { mapGetters } from 'vuex';
72+
import { mapActions, mapGetters } from 'vuex';
7673
import FileStatusText from 'shared/views/files/FileStatusText';
7774
import Uploader from 'shared/views/files/Uploader';
78-
import IconButton from 'shared/views/IconButton';
7975
import { constantsTranslationMixin, fileSizeMixin, fileStatusMixin } from 'shared/mixins';
8076
import FileDropzone from 'shared/views/files/FileDropzone';
8177
@@ -85,7 +81,6 @@
8581
Uploader,
8682
FileDropzone,
8783
FileStatusText,
88-
IconButton,
8984
},
9085
mixins: [constantsTranslationMixin, fileSizeMixin, fileStatusMixin],
9186
props: {
@@ -150,6 +145,36 @@
150145
}
151146
return null;
152147
},
148+
previewFilesOptions() {
149+
const options = [
150+
{
151+
label: this.$tr('replaceFileMenuOptionLabel'),
152+
value: 'REPLACE_FILE',
153+
onClick: replaceFile => {
154+
replaceFile();
155+
},
156+
condition: this.fileDisplay,
157+
},
158+
{
159+
label: this.$tr('downloadMenuOptionLabel'),
160+
value: 'DOWNLOAD_FILE',
161+
onClick: () => {
162+
this.initiateFileDownload();
163+
},
164+
condition: this.fileDisplay,
165+
},
166+
{
167+
label: this.$tr('removeMenuOptionLabel'),
168+
value: 'REMOVE_FILE',
169+
onClick: () => {
170+
this.removeFile();
171+
},
172+
condition: this.fileDisplay && this.allowFileRemove,
173+
},
174+
];
175+
176+
return options.filter(option => option.condition);
177+
},
153178
},
154179
watch: {
155180
'file.id': {
@@ -159,6 +184,8 @@
159184
},
160185
},
161186
methods: {
187+
...mapActions('file', ['downloadFile']),
188+
...mapActions(['showSnackbar']),
162189
completeUpload(fileUpload) {
163190
if (fileUpload.id === this.fileUploadId) {
164191
this.uploadCompleteHandler(fileUpload);
@@ -167,11 +194,30 @@
167194
uploadingHandler(fileUpload) {
168195
this.fileUploadId = fileUpload.id;
169196
},
197+
initiateFileDownload() {
198+
try {
199+
this.downloadFile({
200+
url: this.fileDisplay.url,
201+
fileName: this.formattedFileDisplay,
202+
});
203+
} catch (e) {
204+
this.showSnackbar({
205+
text: this.$tr('downloadFailed'),
206+
});
207+
}
208+
},
209+
removeFile() {
210+
this.$emit('remove', this.file);
211+
},
170212
},
171213
$trs: {
172214
uploadButton: 'Select file',
173-
removeFileButton: 'Remove',
215+
replaceFileMenuOptionLabel: 'Replace file',
216+
downloadMenuOptionLabel: 'Download',
217+
removeMenuOptionLabel: 'Remove',
218+
downloadFailed: 'Failed to download file',
174219
/* eslint-disable kolibri/vue-no-unused-translations */
220+
removeFileButton: 'Remove',
175221
retryUpload: 'Retry upload',
176222
uploadFailed: 'Upload failed',
177223
unknownFile: 'Unknown filename',
@@ -183,36 +229,32 @@
183229

184230
<style lang="scss" scoped>
185231
186-
.layout .section-header {
187-
padding: 0 15px;
188-
font-weight: bold;
189-
color: var(--v-darken-3);
190-
}
191-
192-
button {
193-
margin: 0;
194-
}
195-
196232
::v-deep .v-list__tile {
197233
height: max-content !important;
198234
min-height: 64px;
199235
padding: 5px 16px;
200236
201-
.remove-icon {
202-
display: none;
203-
}
204-
205-
&:hover .remove-icon {
206-
display: block;
237+
&:focus {
238+
background-color: var(--v-grey-lighten5);
239+
outline-color: var(--v-primary-base);
207240
}
208241
209242
.v-list__tile__title {
210-
height: max-content;
243+
height: 30px;
211244
}
212245
213246
.v-list__tile__sub-title {
247+
margin-left: 1px;
214248
white-space: unset;
215249
}
216250
}
217251
252+
.file-display {
253+
margin-left: 1px;
254+
255+
span {
256+
font-size: 15px;
257+
}
258+
}
259+
218260
</style>

0 commit comments

Comments
 (0)