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

Implement recommendations display #4803

Open
wants to merge 39 commits into
base: search-recommendations
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
23e49e6
Adds translator object + strings for search recs feature
akolson Aug 29, 2024
3e85347
change SearchOrBrowserWindow from Vuetify to KDS components
akolson Aug 29, 2024
fe76812
add about recommendations link
akolson Sep 3, 2024
1b5fe71
Update Translator object to expose a destructurable interface for str…
akolson Sep 3, 2024
13c7d15
Merge branch 'search-recs-strings-feature-file' into implement-recomm…
akolson Sep 3, 2024
f51e08f
adds recommendations title
akolson Sep 3, 2024
eeb8537
updates strings
akolson Sep 3, 2024
003d109
Merge branch 'search-recs-strings-feature-file' into implement-recomm…
akolson Sep 3, 2024
a43dcbb
Adds about recommendations modal
akolson Sep 3, 2024
675cdae
updates strings
akolson Sep 3, 2024
c56f907
Merge branch 'search-recs-strings-feature-file' into implement-recomm…
akolson Sep 3, 2024
3532e75
Adds reponsiveness to page
akolson Sep 4, 2024
c8f8db9
Adds sample data request
akolson Sep 5, 2024
fa81206
Merge branch 'merge-into-search-recs' into implement-recommendations-…
akolson Sep 5, 2024
3a74adc
Add latest KDS rc4 as dependency
akolson Sep 6, 2024
835e78c
Adds KCard
akolson Sep 9, 2024
b80aedb
Merge branch 'search-recommendations' into implement-recommendations-…
akolson Sep 18, 2024
e3f0cba
Adds KCardGrid
akolson Sep 24, 2024
93b8ef3
Adds preliminary logic to load recommendations
akolson Oct 31, 2024
078638c
Merge remote-tracking branch 'upstream/unstable' into merge-into-sear…
akolson Oct 31, 2024
4f1f84e
Merge branch 'merge-into-search-recs' into implement-recommendations-…
akolson Oct 31, 2024
1d000da
Merge branch 'merge-into-search-recs' into implement-recommendations-…
akolson Oct 31, 2024
8e200d5
fixes bug in translateMetadataString
akolson Oct 31, 2024
dc29890
Make minor tweaks to UI
akolson Nov 4, 2024
7009c10
updates kds version
akolson Nov 13, 2024
30d397f
Adds pagination logic
akolson Nov 27, 2024
7e98efc
Refactors code
akolson Dec 3, 2024
e4e2eeb
More code refators and logic fixes
akolson Dec 3, 2024
4ce5884
code clean-up
akolson Dec 3, 2024
95a1b52
adds ai flag check on UI and fetch
akolson Dec 4, 2024
0cb9469
Merge remote-tracking branch 'upstream/search-recommendations' into i…
akolson Dec 4, 2024
9f8de26
minor UI fixes
akolson Dec 4, 2024
596e109
further UI improvements
akolson Dec 5, 2024
7574c06
UI fixes
akolson Dec 9, 2024
c6e3a0c
additional UI fixes
akolson Dec 10, 2024
75df365
Updates kds to latest version
akolson Dec 11, 2024
48cda0d
Merge branch 'search-recommendations' into implement-recommendations-…
akolson Dec 13, 2024
47725f3
Add todo to relax an unlikely situation where channel names will be null
akolson Feb 7, 2025
6b85c8d
Removes ambiguous selected proo from recommended resource card
akolson Feb 7, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,36 @@

<KCard
:to="to"
:title="title"
:title="node.title"
layout="horizontal"
:headingLevel="headingLevel"
:headingLevel="2"
thumbnailScaleType="contain"
thumbnailDisplay="small"
thumbnailAlign="right"
:thumbnailSrc="thumbnailSrc"
:thumbnailSrc="node.thumbnail"
>
<template #select>
<KCheckbox />
<Checkbox
:key="`checkbox-${node.id}`"
:inputValue="isSelected(node)"
@input="toggleSelected(node)"
/>
</template>
<template #aboveTitle>
<span>
<KIcon icon="practiceSolid" />
<span>Practice</span>
<ContentNodeLearningActivityIcon
:learningActivities="{ 'wA01urpi': true }"
showEachActivityIcon
includeText
small
class="inline"
/>
</span>
</template>
<template #belowTitle>
<div>
<KTextTruncator
:text="description"
:text="node.description"
:maxLines="2"
/>
</div>
Expand All @@ -40,28 +49,40 @@

<script>

import find from 'lodash/find';
import Checkbox from 'shared/views/form/Checkbox';
import ContentNodeLearningActivityIcon from 'shared/views/ContentNodeLearningActivityIcon';

export default {
name: 'RecommendedResourceCard',
components: {
Checkbox,
ContentNodeLearningActivityIcon,
},
props: {
to: {
type: Object,
required: true,
},
title: {
type: String,
default: null,
},
description: {
type: String,
default: null,
node: {
type: Object,
required: true,
},
headingLevel: {
type: Number,
selected: {
type: Array,
required: true,
},
thumbnailSrc: {
type: String,
default: null,
},
computed: {
isSelected() {
return function(node) {
return Boolean(find(this.selected, { id: node.id }));
};
},
},
methods: {
toggleSelected(node) {
this.$emit('change_selected', { nodes: [node], isSelected: !this.isSelected(node) });
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@
v-for="recommendation in recommendations"
:key="recommendation.id"
:to="{}"
:title="recommendation.title"
:description="recommendation.description"
:headingLevel="2"
:node="recommendation"
:selected.sync="selected"
@change_selected="handleChangeSelected"
Copy link
Member

Choose a reason for hiding this comment

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

I am not super familiar with using .sync so this may just be my own misunderstanding but I'm wondering why we have both a change selection event and a selection prop binding? are they doing different things? I'm also not clear on where handleChangeSelected is coming from

Copy link
Member Author

Choose a reason for hiding this comment

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

The RecommendedResourceCard reuses existing functionality (the selected vuex state and handleChangeSelected handler) used by the main panel to allow for resource imports, as they do pretty much the same thing.

  • The selected state keeps track of what has been selected and deselected.
  • The handleChangeSelected handler updates the selected state.
  • The handleChangeSelected receives an isSelected callback from the clicked checkbox in the recommended resource card and passes back with the associated node selected or deselected
  • The selected prop is only passed for use in the isSelected callback whichI think we can directly declare in the recommended resources card to remove the ambiguity.

/>
</KCardGrid>
</div>
Expand Down Expand Up @@ -151,7 +151,6 @@
import ImportFromChannelsModal from './ImportFromChannelsModal';
import { withChangeTracker } from 'shared/data/changes';
import { searchRecommendationsStrings } from 'shared/strings/searchRecommendationsStrings';
import client from 'shared/client';

export default {
name: 'SearchOrBrowseWindow',
Expand Down Expand Up @@ -244,10 +243,16 @@
},
mounted() {
this.searchTerm = this.$route.params.searchTerm || '';
this.loadSamplePublicContentNode();

this.loadRecommendations().then(recommendations => {
this.loadRecommendedNodes(recommendations).then(nodes => {
this.recommendations = [...this.recommendations, ...nodes.filter(Boolean)];
});
});
},
methods: {
...mapActions('clipboard', ['copy']),
...mapActions('contentNode', ['loadPublicContentNode']),
...mapMutations('importFromChannels', {
selectNodes: 'SELECT_NODES',
deselectNodes: 'DESELECT_NODES',
Expand Down Expand Up @@ -311,14 +316,36 @@
closeAboutRecommendations() {
this.showAboutRecommendations = false;
},
loadSamplePublicContentNode() {
client
.get(
'https://studio.learningequality.org/api/public/v2/contentnode/cd99a903a0a24483ac933402bb452f54/'
)
.then(response => {
this.recommendations = Array(4).fill(response.data);
});
async loadRecommendedNodes(recommendations) {
return await Promise.all(
recommendations.map(async recommendation => {
// This call is cached, so we don't need to worry about multiple calls.
return await this.loadPublicContentNode({
id: recommendation.id,
nodeId: recommendation.node_id,
rootId: recommendation.main_tree_id,
parent: recommendation.parent_id,
}).catch(() => null);
})
).then(nodes => nodes.filter(Boolean));
},
loadRecommendations() {
// This is a placeholder for the actual recommendation logic that interacts with
// the recommender models based on current context. For now, we just load some random nodes.
return Promise.resolve([
{
id: 'b1c252c8faf64500bbb44fcb2162cced',
node_id: '3bd78ad83c064b0c8585e603d7ca4c06',
main_tree_id: 'e98098ce958840f98db61bae6e4781fe',
parent_id: '86ea7baa33f44c5da49c638934f7081d',
},
{
id: '74af5a51ceb4435f9ea973603c17359e',
node_id: 'ab01552b7a5f40cc96121c99a5d99a4f',
main_tree_id: 'e98098ce958840f98db61bae6e4781fe',
parent_id: '86ea7baa33f44c5da49c638934f7081d',
},
]);
},
},
$trs: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"jspdf": "https://github.com/parallax/jsPDF.git#b7a1d8239c596292ce86dafa77f05987bcfa2e6e",
"jszip": "^3.10.1",
"kolibri-constants": "^0.2.0",
"kolibri-design-system": "^5.0.0-rc6",
"kolibri-design-system": "5.0.0-rc7",
AlexVelezLl marked this conversation as resolved.
Show resolved Hide resolved
"lodash": "^4.17.21",
"material-icons": "0.3.1",
"mutex-js": "^1.1.5",
Expand Down
73 changes: 39 additions & 34 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4647,7 +4647,7 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"

color-convert@^1.9.0:
color-convert@^1.9.0, color-convert@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
Expand All @@ -4666,16 +4666,32 @@ [email protected]:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==

color-name@~1.1.4:
color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==

color-string@^1.6.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"

color-support@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==

[email protected]:
version "3.2.1"
resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164"
integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
dependencies:
color-convert "^1.9.3"
color-string "^1.6.0"

colord@^2.9.1, colord@^2.9.2:
version "2.9.2"
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
Expand Down Expand Up @@ -7751,6 +7767,11 @@ is-arrayish@^0.2.1:
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==

is-arrayish@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==

is-bigint@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
Expand Down Expand Up @@ -9374,14 +9395,15 @@ kolibri-constants@^0.2.0:
resolved "https://registry.yarnpkg.com/kolibri-constants/-/kolibri-constants-0.2.5.tgz#2b9df4c477119d0ade2d66bf8aef8a4172f0418f"
integrity sha512-ZoFZ83xgteZhFZtYjiOmITcZeSF+X42i12TOo87zmcdA78jj0dZbPYB+ttO855UxoKY8h4HHeDVZIUkE5TGa5g==

kolibri-design-system@^4.2.0:
version "4.3.1"
resolved "https://registry.yarnpkg.com/kolibri-design-system/-/kolibri-design-system-4.3.1.tgz#09bb207e7507fc3c27f119054151485ffde67dd5"
integrity sha512-umMrqXorU3UzXQZ1ZAmUjYWB02phXcX0qmWwS+FAOPbOjUEjmB6pZ/lN5TjjeE3onZfasf+pjwb3xJx3F4Nn/A==
kolibri-design-system@5.0.0-rc7:
version "5.0.0-rc7"
resolved "https://registry.yarnpkg.com/kolibri-design-system/-/kolibri-design-system-5.0.0-rc7.tgz#3a965b6a0ab9042f6e1ad754a6ebcdb5f1b89da6"
integrity sha512-30lp0aY7maWXX9nwVDTNM49ittwIQgSbViQNw9RS5DLEXLEyJc212pabIytEGidyxmhpVj4gUM/MdwyM606Mxg==
dependencies:
"@vue/composition-api" "1.7.2"
aphrodite "https://github.com/learningequality/aphrodite/"
autosize "3.0.21"
color "3.2.1"
css-element-queries "1.2.0"
date-fns "1.30.1"
frame-throttle "3.0.0"
Expand Down Expand Up @@ -12319,6 +12341,13 @@ signal-exit@^4.0.1:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.1.tgz#96a61033896120ec9335d96851d902cc98f0ba2a"
integrity sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==

simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
dependencies:
is-arrayish "^0.3.1"

sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
Expand Down Expand Up @@ -12692,16 +12721,7 @@ string-trim-spaces-only@^3.1.0:
dependencies:
"@babel/runtime" "^7.14.0"

"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -12847,14 +12867,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1"
is-regexp "^1.0.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

[email protected], strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", [email protected], strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down Expand Up @@ -14560,7 +14573,8 @@ [email protected], workbox-window@^7.0.0:
"@types/trusted-types" "^2.0.2"
workbox-core "7.0.0"

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
name wrap-ansi-cjs
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand All @@ -14578,15 +14592,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
Expand Down