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

[WIP] Media subscription performance improvements #2012

Closed
wants to merge 11 commits into from
8 changes: 8 additions & 0 deletions imports/plugins/core/media/register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Reaction } from "/server/api";

Reaction.registerPackage({
label: "Media",
name: "reaction-media",
icon: "fa fa-picture-o",
autoEnable: true
});
1 change: 1 addition & 0 deletions imports/plugins/core/media/server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./methods.js";
38 changes: 38 additions & 0 deletions imports/plugins/core/media/server/methods.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Meteor } from "meteor/meteor";
import { check, Match } from "meteor/check";
import { Media } from "/lib/collections";
import { Reaction } from "/server/api";

export function updateMediaMetadata(mediaId, metadata) {
check(mediaId, String);

Media.update({ _id: mediaId }, {
$set: {
metadata
}
});
}

export function updateMediaPosition(mediaIdArray) {
check(mediaIdArray, [String]);

mediaIdArray.forEach((mediaId, index) => {
Media.update(mediaId, {
$set: {
"metadata.priority": index
}
});
});
}

export function removeMedia(mediaId) {
check(mediaId, String);

return Media.remove({ _id: mediaId });
}

Meteor.methods({
"media/updateMetadata": updateMediaMetadata,
"media/updatePositions": updateMediaPosition,
"media/remove": removeMedia
});
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ function composer(props, onData) {
parentDocument: {
$in: props.documentIds
}
},
{
"documentData.productId": {
$in: props.documentIds
}
},
{
"documentData.variantId": {
$in: props.documentIds
}
}
],
"workflow.status": {
Expand Down
6 changes: 3 additions & 3 deletions imports/plugins/core/revisions/server/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ Media.files.before.insert((userid, media) => {
documentId: media._id,
documentData: revisionMetadata,
documentType: "image",
parentDocument: media.metadata.productId,
parentDocument: media.metadata.variantId || media.metadata.productId,
changeType: "insert",
workflow: {
status: "revision/update"
Expand Down Expand Up @@ -218,7 +218,7 @@ Media.files.before.update((userId, media, fieldNames, modifier) => {
documentId: media._id,
documentData: convertedMetadata,
documentType: "image",
parentDocument: media.metadata.productId,
parentDocument: media.metadata.variantId || media.metadata.productId,
changeType: "update",
workflow: {
status: "revision/update"
Expand Down Expand Up @@ -249,7 +249,7 @@ Media.files.before.remove((userId, media) => {
documentId: media._id,
documentData: media.metadata,
documentType: "image",
parentDocument: media.metadata.productId,
parentDocument: media.metadata.variantId || media.metadata.productId,
changeType: "remove",
workflow: {
status: "revision/update"
Expand Down
15 changes: 12 additions & 3 deletions imports/plugins/core/ui/client/components/media/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,20 @@ class MediaItem extends Component {
}

get source() {
if (typeof this.props.source === "object" && this.props.source) {
return this.props.source.url() || this.defaultSource;
let imageSrc;

if (this.props.source) {
// Handle FS.File
if (typeof this.props.source.url === "function") {
imageSrc = this.props.source.url();
} else if (typeof this.props.source.images === "object") {
imageSrc = this.props.source.images.large && this.props.source.images.large.url;
} else {
imageSrc = this.props.source;
}
}

return this.props.source || this.defaultSource;
return imageSrc || this.defaultSource;
}

renderImage() {
Expand Down
91 changes: 23 additions & 68 deletions imports/plugins/core/ui/client/containers/mediaGalleryContainer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { Component, PropTypes } from "react";
import Measure from "react-measure";
import update from "react/lib/update";
import { Meteor } from "meteor/meteor";
import { composeWithTracker } from "/lib/api/compose";
import { MediaGallery } from "../components";
import { Reaction } from "/client/api";
import { ReactionProduct } from "/lib/api";
import { Media, Revisions } from "/lib/collections";
import { Media } from "/lib/collections";

function uploadHandler(files) {
// TODO: It would be cool to move this logic to common ValidatedMethod, but
Expand Down Expand Up @@ -72,12 +73,23 @@ class MediaGalleryContainer extends Component {
});
}

get allowFeaturedMediaHover() {
if (this.state.featuredMedia) {
return true;
}
return false;
}

get media() {
return (this.state && this.state.media) || this.props.media;
}

handleDrop = (files) => {
uploadHandler(files);
}

handleRemoveMedia = (media) => {
const imageUrl = media.url();
const imageUrl = media.images && media.images.medium.url;
const mediaId = media._id;

Alerts.alert({
Expand All @@ -88,31 +100,18 @@ class MediaGalleryContainer extends Component {
imageHeight: 150
}, (isConfirm) => {
if (isConfirm) {
Media.remove({ _id: mediaId }, (error) => {
Meteor.call("media/remove", mediaId, (error) => {
if (error) {
Alerts.toast(error.reason, "warning", {
autoHide: 10000
});
}

// updateImagePriorities();
});
}
// show media as removed (since it will not disappear until changes are published
});
}

get allowFeaturedMediaHover() {
if (this.state.featuredMedia) {
return true;
}
return false;
}

get media() {
return (this.state && this.state.media) || this.props.media;
}

handleMouseEnterMedia = (event, media) => {
this.setState({
featuredMedia: media
Expand Down Expand Up @@ -143,14 +142,14 @@ class MediaGalleryContainer extends Component {
});

// Save the updated positions
Meteor.defer(() => {
newMediaOrder.forEach((mediaItem, index) => {
Media.update(mediaItem._id, {
$set: {
"metadata.priority": index
}
const mediaIds = newMediaOrder.map((mediaItem) => mediaItem._id);

Meteor.call("media/updatePositions", mediaIds, (error) => {
if (error) {
Alerts.toast(error.reason, "warning", {
autoHide: 10000
});
});
}
});
}

Expand Down Expand Up @@ -181,54 +180,10 @@ class MediaGalleryContainer extends Component {
}
}

function fetchMediaRevisions() {
const productId = ReactionProduct.selectedProductId();
const mediaRevisions = Revisions.find({
"parentDocument": productId,
"documentType": "image",
"workflow.status": {
$nin: ["revision/published"]
}
}).fetch();
return mediaRevisions;
}

// resort the media in
function sortMedia(media) {
const sortedMedia = _.sortBy(media, function (m) { return m.metadata.priority;});
return sortedMedia;
}

// Search through revisions and if we find one for the image, stick it on the object
function appendRevisionsToMedia(props, media) {
if (!Reaction.hasPermission(props.permission || ["createProduct"])) {
return media;
}
const mediaRevisions = fetchMediaRevisions();
const newMedia = [];
for (const image of media) {
image.revision = undefined;
for (const revision of mediaRevisions) {
if (revision.documentId === image._id) {
image.revision = revision;
image.metadata.priority = revision.documentData.priority;
}
}
newMedia.push(image);
}
return sortMedia(newMedia);
}

function composer(props, onData) {
let media;
let editable;
const viewAs = Reaction.getUserPreferences("reaction-dashboard", "viewAs", "administrator");

if (!props.media) {
// Fetch media based on props
} else {
media = appendRevisionsToMedia(props, props.media);
}
const media = props.media;

if (viewAs === "customer") {
editable = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,28 @@ import { Translation } from "/imports/plugins/core/ui/client/components";
import { MediaItem } from "/imports/plugins/core/ui/client/components";

class ChildVariant extends Component {
static propTypes = {
editButton: PropTypes.node,
isSelected: PropTypes.bool,
onClick: PropTypes.func,
soldOut: PropTypes.bool,
variant: PropTypes.object,
visibilityButton: PropTypes.node
}

handleClick = (event) => {
if (this.props.onClick) {
this.props.onClick(event, this.props.variant);
}
}

get hasMedia() {
return Array.isArray(this.props.media) && this.props.media.length > 0;
return Array.isArray(this.props.variant.media) && this.props.variant.media.length > 0;
}

get primaryMediaItem() {
if (this.hasMedia) {
return this.props.media[0];
return this.props.variant.media[0].images.small;
}

return null;
Expand Down Expand Up @@ -65,7 +74,7 @@ class ChildVariant extends Component {
const media = this.primaryMediaItem;

return (
<MediaItem source={media.url()} />
<MediaItem source={media.url} />
);
}

Expand Down Expand Up @@ -103,15 +112,4 @@ class ChildVariant extends Component {
}
}

ChildVariant.propTypes = {
editButton: PropTypes.node,
isSelected: PropTypes.bool,
media: PropTypes.arrayOf(PropTypes.object),
onClick: PropTypes.func,
soldOut: PropTypes.bool,
variant: PropTypes.object,
visibilityButton: PropTypes.node
};


export default ChildVariant;
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ import { Divider, IconButton } from "/imports/plugins/core/ui/client/components"
import { ChildVariant } from "./";

class VariantList extends Component {
static propTypes = {
childVariants: PropTypes.arrayOf(PropTypes.object),
displayPrice: PropTypes.func,
editable: PropTypes.bool,
isSoldOut: PropTypes.func,
onCreateVariant: PropTypes.func,
onEditVariant: PropTypes.func,
onMoveVariant: PropTypes.func,
onVariantClick: PropTypes.func,
onVariantVisibiltyToggle: PropTypes.func,
variantIsSelected: PropTypes.func,
variants: PropTypes.arrayOf(PropTypes.object)
}

handleVariantEditClick = (event, editButtonProps) => {
if (this.props.onEditVariant) {
Expand Down Expand Up @@ -126,13 +139,6 @@ class VariantList extends Component {

if (this.props.childVariants) {
childVariants = this.props.childVariants.map((childVariant, index) => {
const media = this.props.childVariantMedia.filter((mediaItem) => {
if (mediaItem.metadata.variantId === childVariant._id) {
return true;
}
return false;
});

return (
<EditContainer
data={childVariant}
Expand All @@ -148,7 +154,6 @@ class VariantList extends Component {
>
<ChildVariant
isSelected={this.props.variantIsSelected(childVariant._id)}
media={media}
onClick={this.handleChildleVariantClick}
variant={childVariant}
/>
Expand Down Expand Up @@ -183,19 +188,4 @@ class VariantList extends Component {
}
}

VariantList.propTypes = {
childVariantMedia: PropTypes.arrayOf(PropTypes.any),
childVariants: PropTypes.arrayOf(PropTypes.object),
displayPrice: PropTypes.func,
editable: PropTypes.bool,
isSoldOut: PropTypes.func,
onCreateVariant: PropTypes.func,
onEditVariant: PropTypes.func,
onMoveVariant: PropTypes.func,
onVariantClick: PropTypes.func,
onVariantVisibiltyToggle: PropTypes.func,
variantIsSelected: PropTypes.func,
variants: PropTypes.arrayOf(PropTypes.object)
};

export default VariantList;
Loading