@windward/core 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -19
- package/bitbucket/releases/delete-rc-tags.sh +35 -0
- package/bitbucket/releases/tag-master-release.sh +48 -0
- package/bitbucket-pipelines.yml +3 -1
- package/components/Content/Blocks/Email.vue +27 -17
- package/components/Content/Blocks/HorizontalRule.vue +2 -0
- package/components/Content/Blocks/UserUpload.vue +33 -38
- package/components/Navigation/Items/CourseGlossaryToolNav.vue +7 -1
- package/components/Settings/EmailSettings.vue +31 -6
- package/components/Settings/UserUploadSettings.vue +40 -41
- package/components/utils/GenerateAIQuestionButton.vue +111 -23
- package/i18n/en-US/components/content/blocks/generate_questions.ts +7 -0
- package/i18n/en-US/components/settings/email.ts +3 -0
- package/i18n/es-ES/components/content/blocks/generate_questions.ts +7 -0
- package/i18n/es-ES/components/settings/email.ts +3 -0
- package/i18n/sv-SE/components/content/blocks/generate_questions.ts +7 -0
- package/i18n/sv-SE/components/settings/email.ts +5 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,59 +1,58 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Release [0.20.0] - 2025-07-01
|
|
4
4
|
|
|
5
|
+
* Merge remote-tracking branch 'origin/release/0.20.0' into release/0.20.0
|
|
6
|
+
* Merge remote-tracking branch 'origin/release/0.20.0' into release/0.20.0
|
|
7
|
+
* Merged in feature/LE-1948/empty-bucket-localization-fix (pull request #397)
|
|
8
|
+
* Merged in LE-1911-email-block-to-cc-and-subject-te (pull request #395)
|
|
9
|
+
* Merged in bugfix/LE-1928-user-upload-allowed-file-types (pull request #391)
|
|
10
|
+
* Merged in bugfix/LE-1941-divider-dashed-line-renders-soli (pull request #396)
|
|
11
|
+
* Merged in feature/LE-1948/empty-bucket (pull request #393)
|
|
12
|
+
* Merged in feature/LE-1906-ai-assistant-button-text (pull request #394)
|
|
13
|
+
* Merged in bugfix/LE-1739-email-block-to-cc-and-subject-te (pull request #392)
|
|
14
|
+
* Merged in bugfix/LE-1917-student-experience-cleanup (pull request #386)
|
|
15
|
+
* Merged release/0.19.0 into bugfix/LE-1917-student-experience-cleanup
|
|
5
16
|
|
|
6
|
-
### Release [0.17.0] created - 2025-05-13
|
|
7
17
|
|
|
18
|
+
### Release [0.19.0] created - 2025-05-30
|
|
8
19
|
|
|
9
|
-
### Release [0.
|
|
20
|
+
### Release [0.18.0] created - 2025-05-21
|
|
10
21
|
|
|
22
|
+
### Release [0.17.0] created - 2025-05-13
|
|
11
23
|
|
|
12
|
-
### Release [0.
|
|
24
|
+
### Release [0.16.0] created - 2025-04-29
|
|
13
25
|
|
|
26
|
+
### Release [0.15.0] created - 2025-04-09
|
|
14
27
|
|
|
15
28
|
### Release [0.14.0] created - 2025-03-25
|
|
16
29
|
|
|
17
|
-
|
|
18
30
|
### Release [0.16.0] created - 2025-03-11
|
|
19
31
|
|
|
20
|
-
|
|
21
32
|
### Hotfix [0.12.6] created - 2025-02-26
|
|
22
33
|
|
|
23
|
-
|
|
24
34
|
### Hotfix [0.12.5] created - 2025-02-26
|
|
25
35
|
|
|
26
|
-
|
|
27
36
|
### Hotfix [0.12.4] created - 2025-02-25
|
|
28
37
|
|
|
29
|
-
|
|
30
38
|
### Hotfix [0.12.3] created - 2025-02-21
|
|
31
39
|
|
|
32
|
-
|
|
33
40
|
### Hotfix [0.12.2] created - 2025-02-21
|
|
34
41
|
|
|
35
|
-
|
|
36
42
|
### Hotfix [0.12.1] created - 2025-02-21
|
|
37
43
|
|
|
38
|
-
|
|
39
44
|
### Release [0.12.0] created - 2025-02-18
|
|
40
45
|
|
|
41
|
-
|
|
42
46
|
### Release [0.11.0] created - 2025-02-05
|
|
43
47
|
|
|
44
|
-
|
|
45
48
|
### Release [0.10.0] created - 2025-01-03
|
|
46
49
|
|
|
47
|
-
|
|
48
50
|
### Hotfix [0.9.1] created - 2024-12-10
|
|
49
51
|
|
|
50
|
-
|
|
51
52
|
## Release [0.7.0] - 2024-08-29
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
- Version bump to 0.7.0
|
|
55
55
|
|
|
56
56
|
### Release [0.7.0] created - 2024-08-29
|
|
57
57
|
|
|
58
|
-
|
|
59
58
|
### Release [0.6.0] created - 2024-07-30
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Checkout the release branch
|
|
4
|
+
git checkout master || exit 1
|
|
5
|
+
git pull origin master || exit 1
|
|
6
|
+
|
|
7
|
+
# Configure Git user for the current repository
|
|
8
|
+
git config user.email "commits-noreply@bitbucket.org"
|
|
9
|
+
git config user.name "bitbucket-pipelines"
|
|
10
|
+
|
|
11
|
+
# Extract version from the last merge commit message. Expecting `Merged in xx.xx.xx`
|
|
12
|
+
VERSION=$(basename "$(git log -1 --pretty=%B | grep -o -E "Merged in (release|hotfix)\/([0-9]+\.[0-9]+\.[0-9]+)")")
|
|
13
|
+
|
|
14
|
+
if [ -z "$VERSION" ]; then
|
|
15
|
+
echo "Error: Could not extract version from release branch name."
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "Running auto-rc-tag delete for version $VERSION"
|
|
20
|
+
|
|
21
|
+
# Delete all rc tags for the version
|
|
22
|
+
rc_tags=$(git tag --list "$VERSION-rc*")
|
|
23
|
+
|
|
24
|
+
if [ -n "$rc_tags" ]; then
|
|
25
|
+
echo "Deleting rc tags for version $VERSION..."
|
|
26
|
+
for tag in $rc_tags; do
|
|
27
|
+
git tag -d "$tag"
|
|
28
|
+
git push origin ":refs/tags/$tag"
|
|
29
|
+
done
|
|
30
|
+
echo "All rc tags for version $VERSION have been deleted."
|
|
31
|
+
else
|
|
32
|
+
echo "No rc tags found for version $VERSION."
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
exit 0
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Checkout the release branch
|
|
4
|
+
git checkout master || exit 1
|
|
5
|
+
git pull origin master || exit 1
|
|
6
|
+
|
|
7
|
+
# Configure Git user for the current repository
|
|
8
|
+
git config user.email "commits-noreply@bitbucket.org"
|
|
9
|
+
git config user.name "bitbucket-pipelines"
|
|
10
|
+
|
|
11
|
+
# Extract version from the last merge commit message. Expecting `Merged in xx.xx.xx`
|
|
12
|
+
VERSION=$(basename "$(git log -1 --pretty=%B | grep -o -E "Merged in (release|hotfix)\/([0-9]+\.[0-9]+\.[0-9]+)")")
|
|
13
|
+
|
|
14
|
+
if [ -z "$VERSION" ]; then
|
|
15
|
+
echo "Error: Could not extract version from release branch name."
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "Running auto-tag for version $VERSION"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Fetch the latest state of the repository
|
|
23
|
+
git fetch origin
|
|
24
|
+
|
|
25
|
+
# Get the latest commit on master branch
|
|
26
|
+
LATEST_MASTER_COMMIT=$(git rev-parse origin/master)
|
|
27
|
+
if [ $? -ne 0 ]; then
|
|
28
|
+
echo "Error: Failed to get the latest commit on master"
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Apply the tag to the latest master commit
|
|
33
|
+
git tag -a "$VERSION" -m "Tagging $VERSION" "$LATEST_MASTER_COMMIT"
|
|
34
|
+
if [ $? -ne 0 ]; then
|
|
35
|
+
echo "Error: Failed to tag the commit $LATEST_MASTER_COMMIT with tag $VERSION"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Push the tag to the repository
|
|
40
|
+
git push origin "$VERSION"
|
|
41
|
+
if [ $? -ne 0 ]; then
|
|
42
|
+
echo "Error: Failed to push the tag $VERSION"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
echo "Tag $VERSION successfully applied to commit $LATEST_MASTER_COMMIT and pushed to repository."
|
|
47
|
+
|
|
48
|
+
exit 0
|
package/bitbucket-pipelines.yml
CHANGED
|
@@ -19,4 +19,6 @@ pipelines:
|
|
|
19
19
|
"release/*":
|
|
20
20
|
import: infrastructure-automation:master:auto-update
|
|
21
21
|
"hotfix/*":
|
|
22
|
-
import: infrastructure-automation:master:auto-update
|
|
22
|
+
import: infrastructure-automation:master:auto-update
|
|
23
|
+
master:
|
|
24
|
+
import: infrastructure-automation:master:auto-publish-release
|
|
@@ -7,13 +7,7 @@
|
|
|
7
7
|
"
|
|
8
8
|
>
|
|
9
9
|
<v-col cols="12" class="pa-0">
|
|
10
|
-
<h2
|
|
11
|
-
v-if="
|
|
12
|
-
block.metadata.config.title &&
|
|
13
|
-
block.metadata.config.display_title
|
|
14
|
-
"
|
|
15
|
-
tabindex="0"
|
|
16
|
-
>
|
|
10
|
+
<h2 v-if="block.metadata.config.title" tabindex="0">
|
|
17
11
|
{{ block.metadata.config.title }}
|
|
18
12
|
</h2>
|
|
19
13
|
<p
|
|
@@ -27,8 +21,8 @@
|
|
|
27
21
|
</v-row>
|
|
28
22
|
<v-row>
|
|
29
23
|
<v-expansion-panels
|
|
30
|
-
:key="expansionPanelKey"
|
|
31
24
|
v-model="selectedPanels"
|
|
25
|
+
:key="expansionPanelKey"
|
|
32
26
|
accordion
|
|
33
27
|
>
|
|
34
28
|
<v-container
|
|
@@ -130,23 +124,24 @@
|
|
|
130
124
|
></v-col>
|
|
131
125
|
<v-col
|
|
132
126
|
class="div-details"
|
|
133
|
-
|
|
127
|
+
:style="{ color: detailsTextColor }"
|
|
128
|
+
v-if="item.to || item.cc || item.subject"
|
|
134
129
|
>
|
|
135
|
-
<div class="div-details-to">
|
|
130
|
+
<div v-if="item.to" class="div-details-to">
|
|
136
131
|
{{
|
|
137
132
|
$t(
|
|
138
133
|
'windward.core.components.content.blocks.email.to'
|
|
139
134
|
)
|
|
140
135
|
}}: {{ item.to }}
|
|
141
136
|
</div>
|
|
142
|
-
<div class="div-details-cc">
|
|
137
|
+
<div v-if="item.cc" class="div-details-cc">
|
|
143
138
|
{{
|
|
144
139
|
$t(
|
|
145
140
|
'windward.core.components.content.blocks.email.cc'
|
|
146
141
|
)
|
|
147
142
|
}}: {{ item.cc }}
|
|
148
143
|
</div>
|
|
149
|
-
<div class="div-details-
|
|
144
|
+
<div v-if="item.subject" class="div-details-subject">
|
|
150
145
|
{{
|
|
151
146
|
$t(
|
|
152
147
|
'windward.core.components.content.blocks.email.subject'
|
|
@@ -279,6 +274,16 @@ export default {
|
|
|
279
274
|
selectedPanels: 0,
|
|
280
275
|
}
|
|
281
276
|
},
|
|
277
|
+
computed: {
|
|
278
|
+
detailsTextColor() {
|
|
279
|
+
// Use a different AAA compliant color based on the theme
|
|
280
|
+
if (this.$vuetify.theme.dark) {
|
|
281
|
+
return '#A8A8A8'
|
|
282
|
+
} else {
|
|
283
|
+
return '#595959'
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
},
|
|
282
287
|
watch: {
|
|
283
288
|
render(newValue) {
|
|
284
289
|
if (newValue) {
|
|
@@ -311,7 +316,12 @@ export default {
|
|
|
311
316
|
},
|
|
312
317
|
methods: {
|
|
313
318
|
onRemoveTags(body) {
|
|
314
|
-
|
|
319
|
+
if (typeof body !== 'string') {
|
|
320
|
+
return ''
|
|
321
|
+
}
|
|
322
|
+
let text = body.replace(/ /g, ' ')
|
|
323
|
+
text = text.replace(/\u00A0/g, ' ')
|
|
324
|
+
return text.replace(/(<([^>]+)>)/gi, '').trim()
|
|
315
325
|
},
|
|
316
326
|
async onBeforeSave() {
|
|
317
327
|
this.block.metadata.config.emails.forEach((element) => {
|
|
@@ -333,12 +343,12 @@ export default {
|
|
|
333
343
|
font-size: 12px;
|
|
334
344
|
}
|
|
335
345
|
.div-details {
|
|
336
|
-
|
|
337
|
-
font-size: 10px;
|
|
346
|
+
font-size: 14px;
|
|
338
347
|
margin-top: -25px;
|
|
339
348
|
}
|
|
340
|
-
.div-details-cc
|
|
341
|
-
|
|
349
|
+
.div-details-cc,
|
|
350
|
+
.div-details-subject {
|
|
351
|
+
margin-top: -5px;
|
|
342
352
|
}
|
|
343
353
|
.span-details {
|
|
344
354
|
font-weight: bold;
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
:enrollment="enrollment"
|
|
36
36
|
></DisplayUserFilesTable>
|
|
37
37
|
</v-col>
|
|
38
|
-
<v-col
|
|
38
|
+
<v-col v-if="showUpload" cols="12">
|
|
39
39
|
<div v-if="blockExists">
|
|
40
40
|
<v-form
|
|
41
41
|
ref="form"
|
|
@@ -76,59 +76,23 @@
|
|
|
76
76
|
<script>
|
|
77
77
|
import _ from 'lodash'
|
|
78
78
|
import { mapGetters } from 'vuex'
|
|
79
|
-
import TextViewer from '~/components/Text/TextViewer'
|
|
80
|
-
import TextEditor from '~/components/Text/TextEditor'
|
|
81
79
|
import Uuid from '~/helpers/Uuid'
|
|
82
80
|
import Download from '~/helpers/Download'
|
|
83
|
-
|
|
84
|
-
import UserFileAsset from '../../../models/UserFileAsset'
|
|
85
81
|
import Enrollment from '~/models/Enrollment'
|
|
86
82
|
import ContentBlock from '~/models/ContentBlock'
|
|
87
83
|
import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
|
|
88
84
|
import FileDropZone from '~/components/Core/FileDropZone.vue'
|
|
85
|
+
import UserFileAsset from '../../../models/UserFileAsset'
|
|
89
86
|
|
|
90
87
|
import DisplayUserFilesTable from './UserUpload/DisplayUserFilesTable.vue'
|
|
91
88
|
|
|
92
89
|
export default {
|
|
93
90
|
name: 'UserUpload',
|
|
94
91
|
components: {
|
|
95
|
-
TextEditor,
|
|
96
|
-
TextViewer,
|
|
97
92
|
FileDropZone,
|
|
98
93
|
DisplayUserFilesTable,
|
|
99
94
|
},
|
|
100
95
|
extends: BaseContentBlock,
|
|
101
|
-
beforeMount() {
|
|
102
|
-
if (_.isEmpty(this.block)) {
|
|
103
|
-
this.block = {}
|
|
104
|
-
}
|
|
105
|
-
// Default the instructions to collapsed
|
|
106
|
-
this.block.__expandInstructions = false
|
|
107
|
-
|
|
108
|
-
if (_.isEmpty(this.block.body)) {
|
|
109
|
-
this.block.body = this.$t(
|
|
110
|
-
'windward.core.shared.content_blocks.title.user_upload'
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
if (_.isEmpty(this.block.metadata)) {
|
|
114
|
-
this.block.metadata = {}
|
|
115
|
-
}
|
|
116
|
-
if (_.isEmpty(this.block.metadata.config)) {
|
|
117
|
-
this.block.metadata.config = {}
|
|
118
|
-
}
|
|
119
|
-
if (!_.isBoolean(this.block.metadata.config.display_title)) {
|
|
120
|
-
this.$set(this.block.metadata.config, 'display_title', true)
|
|
121
|
-
}
|
|
122
|
-
if (_.isEmpty(this.block.metadata.config.instructions)) {
|
|
123
|
-
this.block.metadata.config.instructions = ''
|
|
124
|
-
}
|
|
125
|
-
if (_.isEmpty(this.block.metadata.config.uploadSettings)) {
|
|
126
|
-
this.block.metadata.config.uploadSettings = {
|
|
127
|
-
multiple: false,
|
|
128
|
-
accept: '',
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
96
|
data() {
|
|
133
97
|
return {
|
|
134
98
|
Download,
|
|
@@ -201,6 +165,37 @@ export default {
|
|
|
201
165
|
}
|
|
202
166
|
},
|
|
203
167
|
},
|
|
168
|
+
beforeMount() {
|
|
169
|
+
if (_.isEmpty(this.block)) {
|
|
170
|
+
this.block = {}
|
|
171
|
+
}
|
|
172
|
+
// Default the instructions to collapsed
|
|
173
|
+
this.block.__expandInstructions = false
|
|
174
|
+
|
|
175
|
+
if (_.isEmpty(this.block.body)) {
|
|
176
|
+
this.block.body = this.$t(
|
|
177
|
+
'windward.core.shared.content_blocks.title.user_upload'
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
if (_.isEmpty(this.block.metadata)) {
|
|
181
|
+
this.block.metadata = {}
|
|
182
|
+
}
|
|
183
|
+
if (_.isEmpty(this.block.metadata.config)) {
|
|
184
|
+
this.block.metadata.config = {}
|
|
185
|
+
}
|
|
186
|
+
if (!_.isBoolean(this.block.metadata.config.display_title)) {
|
|
187
|
+
this.$set(this.block.metadata.config, 'display_title', true)
|
|
188
|
+
}
|
|
189
|
+
if (_.isEmpty(this.block.metadata.config.instructions)) {
|
|
190
|
+
this.block.metadata.config.instructions = ''
|
|
191
|
+
}
|
|
192
|
+
if (_.isEmpty(this.block.metadata.config.uploadSettings)) {
|
|
193
|
+
this.block.metadata.config.uploadSettings = {
|
|
194
|
+
multiple: false,
|
|
195
|
+
accept: '',
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
204
199
|
mounted() {
|
|
205
200
|
if (this.blockExists) {
|
|
206
201
|
this.loadUserUploads()
|
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
<template #form="{ on, attrs }">
|
|
11
11
|
<div v-bind="attrs" v-on="on">
|
|
12
12
|
<v-alert
|
|
13
|
-
v-if="
|
|
13
|
+
v-if="
|
|
14
|
+
!$ContextService.courseInSourceOrganization() &&
|
|
15
|
+
$PermissionService.userHasAccessTo(
|
|
16
|
+
'plugin.windward.core.organization.course.glossary',
|
|
17
|
+
'writable'
|
|
18
|
+
)
|
|
19
|
+
"
|
|
14
20
|
type="warning"
|
|
15
21
|
>
|
|
16
22
|
{{
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
'windward.core.shared.settings.title.click_to_enter'
|
|
24
24
|
)
|
|
25
25
|
}}</template>
|
|
26
|
-
<template #body="{
|
|
26
|
+
<template #body="{ index }">
|
|
27
27
|
<v-container :key="expansionPanelKey">
|
|
28
28
|
<v-text-field
|
|
29
29
|
v-model="block.metadata.config.emails[index].from"
|
|
30
|
-
:rules="
|
|
30
|
+
:rules="getFromRules()"
|
|
31
31
|
:counter="$Validation.getLimit('shortInput')"
|
|
32
32
|
outlined
|
|
33
33
|
:label="
|
|
@@ -36,20 +36,22 @@
|
|
|
36
36
|
)
|
|
37
37
|
"
|
|
38
38
|
:disabled="render"
|
|
39
|
+
required
|
|
39
40
|
></v-text-field>
|
|
40
41
|
<v-text-field
|
|
41
42
|
v-model="block.metadata.config.emails[index].to"
|
|
42
|
-
:rules="
|
|
43
|
+
:rules="getToRules()"
|
|
43
44
|
:counter="$Validation.getLimit('shortInput')"
|
|
44
45
|
outlined
|
|
45
46
|
:label="
|
|
46
47
|
$t('windward.core.components.settings.email.to')
|
|
47
48
|
"
|
|
48
49
|
:disabled="render"
|
|
50
|
+
required
|
|
49
51
|
></v-text-field>
|
|
50
52
|
<v-text-field
|
|
51
53
|
v-model="block.metadata.config.emails[index].cc"
|
|
52
|
-
:rules="
|
|
54
|
+
:rules="getCcRules()"
|
|
53
55
|
:counter="$Validation.getLimit('shortInput')"
|
|
54
56
|
outlined
|
|
55
57
|
:label="
|
|
@@ -61,7 +63,7 @@
|
|
|
61
63
|
v-model="
|
|
62
64
|
block.metadata.config.emails[index].subject
|
|
63
65
|
"
|
|
64
|
-
:rules="
|
|
66
|
+
:rules="getSubjectRules()"
|
|
65
67
|
:counter="$Validation.getLimit('shortInput')"
|
|
66
68
|
outlined
|
|
67
69
|
:label="
|
|
@@ -70,6 +72,7 @@
|
|
|
70
72
|
)
|
|
71
73
|
"
|
|
72
74
|
:disabled="render"
|
|
75
|
+
required
|
|
73
76
|
></v-text-field>
|
|
74
77
|
<v-btn
|
|
75
78
|
class="mb-4"
|
|
@@ -249,9 +252,31 @@ export default {
|
|
|
249
252
|
onDragged() {
|
|
250
253
|
// need to remount body after dragged to update the content body on the element
|
|
251
254
|
this.expansionPanelKey = Crypto.id()
|
|
252
|
-
//close all panels on drag, leaving them open confuses the tracking as indexes changes around
|
|
255
|
+
// close all panels on drag, leaving them open confuses the tracking as indexes changes around
|
|
253
256
|
this.block.metadata.config.selectedPanels = null
|
|
254
257
|
},
|
|
258
|
+
getFromRules() {
|
|
259
|
+
return [
|
|
260
|
+
...this.$Validation.getRule('shortInput'),
|
|
261
|
+
...this.$Validation.getRule('exists'),
|
|
262
|
+
]
|
|
263
|
+
},
|
|
264
|
+
getToRules() {
|
|
265
|
+
return [
|
|
266
|
+
...this.$Validation.getRule('shortInput'),
|
|
267
|
+
...this.$Validation.getRule('exists'),
|
|
268
|
+
]
|
|
269
|
+
},
|
|
270
|
+
getCcRules() {
|
|
271
|
+
// CC field is not required, so only apply length validation
|
|
272
|
+
return this.$Validation.getRule('shortInput')
|
|
273
|
+
},
|
|
274
|
+
getSubjectRules() {
|
|
275
|
+
return [
|
|
276
|
+
...this.$Validation.getRule('shortInput'),
|
|
277
|
+
...this.$Validation.getRule('exists'),
|
|
278
|
+
]
|
|
279
|
+
},
|
|
255
280
|
},
|
|
256
281
|
}
|
|
257
282
|
</script>
|
|
@@ -35,50 +35,11 @@ import BaseContentSettings from '~/components/Content/Settings/BaseContentSettin
|
|
|
35
35
|
import _ from 'lodash'
|
|
36
36
|
import Uuid from '~/helpers/Uuid'
|
|
37
37
|
import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
|
|
38
|
-
import TextEditor from '~/components/Text/TextEditor'
|
|
39
38
|
|
|
40
39
|
export default {
|
|
41
40
|
name: 'UserUploadSettings',
|
|
42
|
-
components: {
|
|
41
|
+
components: { BaseContentBlockSettings },
|
|
43
42
|
extends: BaseContentSettings,
|
|
44
|
-
beforeMount() {
|
|
45
|
-
if (_.isEmpty(this.block)) {
|
|
46
|
-
this.block = {}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (_.isEmpty(this.block.body)) {
|
|
50
|
-
this.block.body = this.$t(
|
|
51
|
-
'windward.core.shared.content_blocks.title.user_upload'
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
if (_.isEmpty(this.block.metadata)) {
|
|
55
|
-
this.block.metadata = {}
|
|
56
|
-
}
|
|
57
|
-
if (_.isEmpty(this.block.metadata.config)) {
|
|
58
|
-
this.block.metadata.config = {}
|
|
59
|
-
}
|
|
60
|
-
if (_.isEmpty(this.block.metadata.config.title)) {
|
|
61
|
-
this.block.metadata.config.title = ''
|
|
62
|
-
}
|
|
63
|
-
if (!_.isBoolean(this.block.metadata.config.display_title)) {
|
|
64
|
-
this.$set(this.block.metadata.config, 'display_title', true)
|
|
65
|
-
}
|
|
66
|
-
if (
|
|
67
|
-
_.isEmpty(this.block.metadata.config.instructions) &&
|
|
68
|
-
this.block.id &&
|
|
69
|
-
!Uuid.test(this.block.id)
|
|
70
|
-
) {
|
|
71
|
-
this.block.metadata.config.instructions = this.$t(
|
|
72
|
-
'windward.core.components.settings.user_upload.instructions'
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
if (_.isEmpty(this.block.metadata.config.uploadSettings)) {
|
|
76
|
-
this.block.metadata.config.uploadSettings = {
|
|
77
|
-
multiple: false,
|
|
78
|
-
accept: '',
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
},
|
|
82
43
|
data() {
|
|
83
44
|
return {
|
|
84
45
|
valid: true,
|
|
@@ -89,7 +50,7 @@ export default {
|
|
|
89
50
|
name: this.$t(
|
|
90
51
|
'windward.core.components.settings.user_upload.types.all'
|
|
91
52
|
),
|
|
92
|
-
value: '
|
|
53
|
+
value: 'image/jpeg,image/gif,image/png,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/zip',
|
|
93
54
|
},
|
|
94
55
|
{
|
|
95
56
|
name: this.$t(
|
|
@@ -123,6 +84,44 @@ export default {
|
|
|
123
84
|
},
|
|
124
85
|
}
|
|
125
86
|
},
|
|
87
|
+
beforeMount() {
|
|
88
|
+
if (_.isEmpty(this.block)) {
|
|
89
|
+
this.block = {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (_.isEmpty(this.block.body)) {
|
|
93
|
+
this.block.body = this.$t(
|
|
94
|
+
'windward.core.shared.content_blocks.title.user_upload'
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
if (_.isEmpty(this.block.metadata)) {
|
|
98
|
+
this.block.metadata = {}
|
|
99
|
+
}
|
|
100
|
+
if (_.isEmpty(this.block.metadata.config)) {
|
|
101
|
+
this.block.metadata.config = {}
|
|
102
|
+
}
|
|
103
|
+
if (_.isEmpty(this.block.metadata.config.title)) {
|
|
104
|
+
this.block.metadata.config.title = ''
|
|
105
|
+
}
|
|
106
|
+
if (!_.isBoolean(this.block.metadata.config.display_title)) {
|
|
107
|
+
this.$set(this.block.metadata.config, 'display_title', true)
|
|
108
|
+
}
|
|
109
|
+
if (
|
|
110
|
+
_.isEmpty(this.block.metadata.config.instructions) &&
|
|
111
|
+
this.block.id &&
|
|
112
|
+
!Uuid.test(this.block.id)
|
|
113
|
+
) {
|
|
114
|
+
this.block.metadata.config.instructions = this.$t(
|
|
115
|
+
'windward.core.components.settings.user_upload.instructions'
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
if (_.isEmpty(this.block.metadata.config.uploadSettings)) {
|
|
119
|
+
this.block.metadata.config.uploadSettings = {
|
|
120
|
+
multiple: false,
|
|
121
|
+
accept: '',
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
126
125
|
mounted() {},
|
|
127
126
|
beforeDestroy() {
|
|
128
127
|
if (this.debouncer) {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
item-text="text"
|
|
31
31
|
class="btn-selector"
|
|
32
32
|
outlined
|
|
33
|
-
hide-details
|
|
33
|
+
:hide-details="!isBucketGameType"
|
|
34
34
|
dense
|
|
35
35
|
:label="
|
|
36
36
|
$t(
|
|
@@ -39,11 +39,14 @@
|
|
|
39
39
|
"
|
|
40
40
|
return-object
|
|
41
41
|
></v-select>
|
|
42
|
+
<div v-if="isBucketGameType" class="text-caption mt-1">
|
|
43
|
+
{{ $t('windward.core.components.content.blocks.generate_questions.replaces_content') }}
|
|
44
|
+
</div>
|
|
42
45
|
</v-col>
|
|
43
46
|
<v-col
|
|
47
|
+
v-if="isFlashcardType"
|
|
44
48
|
cols="auto"
|
|
45
49
|
class="d-flex align-center"
|
|
46
|
-
v-if="isFlashcardType"
|
|
47
50
|
>
|
|
48
51
|
<v-switch
|
|
49
52
|
v-model="replaceExisting"
|
|
@@ -51,11 +54,7 @@
|
|
|
51
54
|
dense
|
|
52
55
|
color="secondary"
|
|
53
56
|
class="mt-0 pt-0"
|
|
54
|
-
:label="
|
|
55
|
-
$t(
|
|
56
|
-
'windward.games.components.settings.flashcard.form.replace_existing'
|
|
57
|
-
)
|
|
58
|
-
"
|
|
57
|
+
:label="replaceExistingLabel"
|
|
59
58
|
:disabled="isLoading"
|
|
60
59
|
></v-switch>
|
|
61
60
|
</v-col>
|
|
@@ -71,11 +70,7 @@
|
|
|
71
70
|
<v-icon v-if="!isLoading" class="pr-1"
|
|
72
71
|
>mdi-magic-staff</v-icon
|
|
73
72
|
>
|
|
74
|
-
{{
|
|
75
|
-
$t(
|
|
76
|
-
'windward.core.components.content.blocks.generate_questions.button_label'
|
|
77
|
-
)
|
|
78
|
-
}}
|
|
73
|
+
{{ buttonLabel }}
|
|
79
74
|
<template v-slot:loader>
|
|
80
75
|
<v-progress-circular
|
|
81
76
|
indeterminate
|
|
@@ -116,7 +111,7 @@ export default {
|
|
|
116
111
|
'windward.core.components.content.blocks.generate_questions.blooms.none'
|
|
117
112
|
),
|
|
118
113
|
},
|
|
119
|
-
replaceExisting: this.replaceExistingMode,
|
|
114
|
+
replaceExisting: this.questionType === 'bucket_game' ? true : this.replaceExistingMode,
|
|
120
115
|
}
|
|
121
116
|
},
|
|
122
117
|
computed: {
|
|
@@ -126,6 +121,19 @@ export default {
|
|
|
126
121
|
isFlashcardType() {
|
|
127
122
|
return this.questionType === 'flashcard'
|
|
128
123
|
},
|
|
124
|
+
isBucketGameType() {
|
|
125
|
+
return this.questionType === 'bucket_game'
|
|
126
|
+
},
|
|
127
|
+
replaceExistingLabel() {
|
|
128
|
+
if (this.isBucketGameType) {
|
|
129
|
+
return this.$t(
|
|
130
|
+
'windward.games.components.settings.bucket_game.form.replace_existing'
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
return this.$t(
|
|
134
|
+
'windward.games.components.settings.flashcard.form.replace_existing'
|
|
135
|
+
)
|
|
136
|
+
},
|
|
129
137
|
flattenedContent() {
|
|
130
138
|
let cloneContentTree = _.cloneDeep(this.contentTree)
|
|
131
139
|
const homepage = this.$ContentService.getHomepage()
|
|
@@ -184,9 +192,10 @@ export default {
|
|
|
184
192
|
]
|
|
185
193
|
|
|
186
194
|
// Only add higher-level Bloom's taxonomy for supported question types
|
|
187
|
-
// Flashcards use only basic levels
|
|
195
|
+
// Flashcards and bucket games use only basic levels
|
|
188
196
|
if (
|
|
189
197
|
!this.isFlashcardType &&
|
|
198
|
+
!this.isBucketGameType &&
|
|
190
199
|
(this.questionType === 'multi_choice_single_answer' ||
|
|
191
200
|
this.questionType === 'ordering' ||
|
|
192
201
|
this.questionType === 'multi_choice_multi_answer')
|
|
@@ -209,6 +218,21 @@ export default {
|
|
|
209
218
|
}
|
|
210
219
|
return basicBloomTaxonomy
|
|
211
220
|
},
|
|
221
|
+
buttonLabel() {
|
|
222
|
+
if (this.questionType === 'flashcard') {
|
|
223
|
+
return this.$t(
|
|
224
|
+
'windward.core.components.content.blocks.generate_questions.button_label_flashcard'
|
|
225
|
+
)
|
|
226
|
+
} else if (this.questionType === 'bucket_game') {
|
|
227
|
+
return this.$t(
|
|
228
|
+
'windward.core.components.content.blocks.generate_questions.button_label_bucket_game'
|
|
229
|
+
)
|
|
230
|
+
} else {
|
|
231
|
+
return this.$t(
|
|
232
|
+
'windward.core.components.content.blocks.generate_questions.button_label'
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
},
|
|
212
236
|
},
|
|
213
237
|
methods: {
|
|
214
238
|
async generateAIQuestion() {
|
|
@@ -277,6 +301,52 @@ export default {
|
|
|
277
301
|
'Invalid response from flashcard generation'
|
|
278
302
|
)
|
|
279
303
|
}
|
|
304
|
+
} else if (this.questionType === 'bucket_game') {
|
|
305
|
+
// BUCKET GAME GENERATION
|
|
306
|
+
const activity = new Activity()
|
|
307
|
+
|
|
308
|
+
const endpoint = `suggest/bucket_game${bloomsRequest}`
|
|
309
|
+
|
|
310
|
+
response = await Activity.custom(
|
|
311
|
+
course,
|
|
312
|
+
content,
|
|
313
|
+
activity,
|
|
314
|
+
endpoint
|
|
315
|
+
).get()
|
|
316
|
+
|
|
317
|
+
let activityData = null
|
|
318
|
+
|
|
319
|
+
if (response && response.activity) {
|
|
320
|
+
activityData = response.activity
|
|
321
|
+
} else if (
|
|
322
|
+
response &&
|
|
323
|
+
response.length > 0 &&
|
|
324
|
+
response[0] &&
|
|
325
|
+
response[0].activity
|
|
326
|
+
) {
|
|
327
|
+
activityData = response[0].activity
|
|
328
|
+
} else if (Array.isArray(response) && response.length > 0) {
|
|
329
|
+
activityData = response[0]
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (
|
|
333
|
+
activityData &&
|
|
334
|
+
activityData.metadata &&
|
|
335
|
+
activityData.metadata.config &&
|
|
336
|
+
activityData.metadata.config.bucket_titles &&
|
|
337
|
+
activityData.metadata.config.bucket_answers
|
|
338
|
+
) {
|
|
339
|
+
// For bucket games, always use replace mode
|
|
340
|
+
this.$emit(
|
|
341
|
+
'click:generate',
|
|
342
|
+
activityData,
|
|
343
|
+
true
|
|
344
|
+
)
|
|
345
|
+
} else {
|
|
346
|
+
throw new Error(
|
|
347
|
+
'Invalid response from bucket game generation'
|
|
348
|
+
)
|
|
349
|
+
}
|
|
280
350
|
} else {
|
|
281
351
|
// ASSESSMENT QUESTION GENERATION
|
|
282
352
|
const assessment = new Assessment({ id: this.block.id })
|
|
@@ -308,16 +378,32 @@ export default {
|
|
|
308
378
|
const basePath =
|
|
309
379
|
'windward.core.components.content.blocks.generate_questions.error'
|
|
310
380
|
|
|
311
|
-
let errorText =
|
|
312
|
-
this.$t(`${basePath}.${errorType}`) +
|
|
313
|
-
'\n\n' +
|
|
314
|
-
this.$t(`${basePath}.${errorType}_support`)
|
|
381
|
+
let errorText = ''
|
|
315
382
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
'
|
|
320
|
-
|
|
383
|
+
// Check for content mismatch error specifically for bucket games
|
|
384
|
+
if (
|
|
385
|
+
(errorMessage === 'activity.error.content_mismatch' ||
|
|
386
|
+
errorType === 'content_mismatch') &&
|
|
387
|
+
this.questionType === 'bucket_game'
|
|
388
|
+
) {
|
|
389
|
+
errorText =
|
|
390
|
+
this.$t(`${basePath}.content_mismatch_bucket_game`) +
|
|
391
|
+
'\n\n' +
|
|
392
|
+
this.$t(
|
|
393
|
+
`${basePath}.content_mismatch_bucket_game_support`
|
|
394
|
+
)
|
|
395
|
+
} else {
|
|
396
|
+
errorText =
|
|
397
|
+
this.$t(`${basePath}.${errorType}`) +
|
|
398
|
+
'\n\n' +
|
|
399
|
+
this.$t(`${basePath}.${errorType}_support`)
|
|
400
|
+
|
|
401
|
+
if (errorType === 'technical') {
|
|
402
|
+
const errorCode =
|
|
403
|
+
error.response?.data?.error?.details?.error_type ||
|
|
404
|
+
'UNKNOWN'
|
|
405
|
+
errorText = errorText.replace('[ERROR_CODE]', errorCode)
|
|
406
|
+
}
|
|
321
407
|
}
|
|
322
408
|
|
|
323
409
|
this.$dialog.error(errorText, {
|
|
@@ -343,3 +429,5 @@ export default {
|
|
|
343
429
|
border-radius: 15px;
|
|
344
430
|
}
|
|
345
431
|
</style>
|
|
432
|
+
}
|
|
433
|
+
</style>
|
|
@@ -12,6 +12,10 @@ export default {
|
|
|
12
12
|
content_mismatch_support:
|
|
13
13
|
"The current content isn't suitable for this type of question. Consider adding more specific examples, numerical data, or comparable items depending on your desired question type.",
|
|
14
14
|
|
|
15
|
+
content_mismatch_bucket_game: "Content not suitable for bucket games.",
|
|
16
|
+
content_mismatch_bucket_game_support:
|
|
17
|
+
"Consider adding content with clear categories and multiple sortable items that can be grouped into 2-4 distinct buckets.",
|
|
18
|
+
|
|
15
19
|
llm_unavailable: 'Question generation temporarily unavailable.',
|
|
16
20
|
llm_unavailable_support:
|
|
17
21
|
"We're unable to connect to our AI service at the moment. Please try again in a few minutes or contact support if the issue persists.",
|
|
@@ -21,6 +25,8 @@ export default {
|
|
|
21
25
|
'Something went wrong on our end. Please try again or contact support if this continues. Reference code: [ERROR_CODE]',
|
|
22
26
|
},
|
|
23
27
|
button_label: 'Generate Question',
|
|
28
|
+
button_label_flashcard: 'Generate Flashcards',
|
|
29
|
+
button_label_bucket_game: 'Generate Buckets',
|
|
24
30
|
selected_pages: 'Selected Page',
|
|
25
31
|
ai_assistance: 'AI Assistance',
|
|
26
32
|
blooms: {
|
|
@@ -32,4 +38,5 @@ export default {
|
|
|
32
38
|
analyze: 'Analyze',
|
|
33
39
|
evaluate: 'Evaluate',
|
|
34
40
|
},
|
|
41
|
+
replaces_content: 'Replaces current block content.',
|
|
35
42
|
}
|
|
@@ -14,6 +14,10 @@ export default {
|
|
|
14
14
|
content_mismatch_support:
|
|
15
15
|
'Por favor, añada más texto, ejemplos o explicaciones a esta sección. Recomendamos al menos 50 palabras de contenido relevante para generar preguntas apropiadas.',
|
|
16
16
|
|
|
17
|
+
content_mismatch_bucket_game: 'El contenido no es adecuado para juegos de categorías.',
|
|
18
|
+
content_mismatch_bucket_game_support:
|
|
19
|
+
'Considera agregar contenido con categorías claras y múltiples elementos clasificables que se puedan agrupar en 2-4 categorías distintas.',
|
|
20
|
+
|
|
17
21
|
llm_unavailable:
|
|
18
22
|
'La generación de preguntas no está disponible temporalmente.',
|
|
19
23
|
llm_unavailable_support:
|
|
@@ -24,6 +28,8 @@ export default {
|
|
|
24
28
|
'Algo salió mal. Inténtalo de nuevo o ponte en contacto con el servicio de asistencia si el problema persiste.',
|
|
25
29
|
},
|
|
26
30
|
button_label: 'Generar pregunta',
|
|
31
|
+
button_label_flashcard: 'Generar tarjetas',
|
|
32
|
+
button_label_bucket_game: 'Generar categorías',
|
|
27
33
|
selected_pages: 'Página seleccionada',
|
|
28
34
|
ai_assistance: 'Asistencia de IA',
|
|
29
35
|
blooms: {
|
|
@@ -35,4 +41,5 @@ export default {
|
|
|
35
41
|
analyze: 'Analizar',
|
|
36
42
|
evaluate: 'Evaluar',
|
|
37
43
|
},
|
|
44
|
+
replaces_content: 'Reemplaza el contenido del bloque actual.',
|
|
38
45
|
}
|
|
@@ -7,4 +7,7 @@ export default {
|
|
|
7
7
|
cc: 'CC',
|
|
8
8
|
body: 'Cuerpo del correo electrónico',
|
|
9
9
|
placeholder: 'Texto del cuerpo del correo electrónico',
|
|
10
|
+
from_required: 'El campo De es obligatorio',
|
|
11
|
+
to_required: 'El campo Para es obligatorio',
|
|
12
|
+
subject_required: 'El campo Asunto es obligatorio',
|
|
10
13
|
}
|
|
@@ -12,6 +12,10 @@ export default {
|
|
|
12
12
|
content_mismatch_support:
|
|
13
13
|
'Vänligen lägg till mer text, exempel eller förklaringar till detta avsnitt. Vi rekommenderar minst 50 ord av relevant innehåll för att generera lämpliga frågor.',
|
|
14
14
|
|
|
15
|
+
content_mismatch_bucket_game: 'Innehållet är inte lämpligt för kategorispel.',
|
|
16
|
+
content_mismatch_bucket_game_support:
|
|
17
|
+
'Överväg att lägga till innehåll med tydliga kategorier och flera sorterbara objekt som kan grupperas i 2-4 distinkta kategorier.',
|
|
18
|
+
|
|
15
19
|
llm_unavailable: 'Frågegenerering tillfälligt otillgänglig.',
|
|
16
20
|
llm_unavailable_support:
|
|
17
21
|
'Vi kan inte ansluta till vår AI-tjänst för tillfället. Försök igen om några minuter.',
|
|
@@ -21,6 +25,8 @@ export default {
|
|
|
21
25
|
'Något gick fel. Försök igen eller kontakta supporten om detta fortsätter.',
|
|
22
26
|
},
|
|
23
27
|
button_label: 'Generera fråga',
|
|
28
|
+
button_label_flashcard: 'Generera flashkort',
|
|
29
|
+
button_label_bucket_game: 'Generera kategorier',
|
|
24
30
|
selected_pages: 'Vald sida',
|
|
25
31
|
ai_assistance: 'AI-hjälp',
|
|
26
32
|
blooms: {
|
|
@@ -32,4 +38,5 @@ export default {
|
|
|
32
38
|
analyze: 'Analysera',
|
|
33
39
|
evaluate: 'Utvärdera',
|
|
34
40
|
},
|
|
41
|
+
replaces_content: 'Ersätter aktuellt blockinnehåll.',
|
|
35
42
|
}
|
|
@@ -4,7 +4,10 @@ export default {
|
|
|
4
4
|
subject: 'Ämne',
|
|
5
5
|
from: 'Från',
|
|
6
6
|
to: 'Till',
|
|
7
|
-
cc: '
|
|
7
|
+
cc: 'Kopia',
|
|
8
8
|
body: 'E-posttext',
|
|
9
|
-
placeholder: 'E-
|
|
9
|
+
placeholder: 'E-posttext',
|
|
10
|
+
from_required: 'Från-fältet är obligatoriskt',
|
|
11
|
+
to_required: 'Till-fältet är obligatoriskt',
|
|
12
|
+
subject_required: 'Ämne-fältet är obligatoriskt',
|
|
10
13
|
}
|