Fix for errors on changing channel availability (#1264)

* Add array diff util

* Use arrayDiff instead of diff

* Update changelog
This commit is contained in:
Krzysztof Wolski 2021-07-29 17:22:44 +02:00 committed by GitHub
parent cacf3030a2
commit 79e752cdbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 112 additions and 55 deletions

View file

@ -72,6 +72,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Use MacawUI - #1229 by @dominik-zeglen
- Add Metadata for Sale & Voucher - #7653 by @piotrgrundas
- Add variant create options dialog - #1238 by @orzechdev
- Fix for errors on changing channel availability - #1264 by @krzysztofwolski
# 2.11.1

View file

@ -20,6 +20,7 @@ import usePaginator, {
} from "@saleor/hooks/usePaginator";
import { commonMessages, errorMessages } from "@saleor/intl";
import useProductSearch from "@saleor/searches/useProductSearch";
import { arrayDiff } from "@saleor/utils/arrays";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
import { mapEdgesToItems } from "@saleor/utils/maps";
@ -28,7 +29,6 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { getParsedDataForJsonStringField } from "@saleor/utils/richText/misc";
import { diff } from "fast-array-diff";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -215,11 +215,14 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
input
}
});
const diffChannels = diff(
collectionChannelsChoices,
formData.channelListings,
(a, b) => a.id === b.id
const initialIds = collectionChannelsChoices.map(
channel => channel.id
);
const modifiedIds = formData.channelListings.map(
channel => channel.id
);
const idsDiff = arrayDiff(initialIds, modifiedIds);
updateChannels({
variables: {
@ -230,10 +233,7 @@ export const CollectionDetails: React.FC<CollectionDetailsProps> = ({
isPublished: channel.isPublished,
publicationDate: channel.publicationDate
})),
removeChannels:
diffChannels.removed?.map(
removedChannel => removedChannel.id
) || []
removeChannels: idsDiff.removed
}
}
});

View file

@ -5,7 +5,8 @@ import { DiscountTypeEnum, RequirementsPicker } from "@saleor/discounts/types";
import { ChangeEvent, FormChange } from "@saleor/hooks/useForm";
import { RequireOnlyOne } from "@saleor/misc";
import { VoucherTypeEnum } from "@saleor/types/globalTypes";
import { diff } from "fast-array-diff";
import { arrayDiff } from "@saleor/utils/arrays";
export interface ChannelArgs {
discountValue: string;
minSpent: string;
@ -96,13 +97,10 @@ export const getChannelsVariables = (
formData: VoucherDetailsPageFormData,
prevChannels?: ChannelVoucherData[]
) => {
const removeChannels = prevChannels
? diff(
prevChannels,
formData.channelListings,
(a, b) => a.id === b.id
).removed?.map(removedChannel => removedChannel.id)
: [];
const initialIds = prevChannels.map(channel => channel.id);
const modifiedIds = formData.channelListings.map(channel => channel.id);
const idsDiff = arrayDiff(initialIds, modifiedIds);
return {
id,
@ -121,7 +119,7 @@ export const getChannelsVariables = (
? 0
: channel.minSpent
})) || [],
removeChannels
removeChannels: idsDiff.removed
}
};
};
@ -131,13 +129,10 @@ export const getSaleChannelsVariables = (
formData: SaleDetailsPageFormData,
prevChannels?: ChannelSaleData[]
) => {
const removeChannels = prevChannels
? diff(
prevChannels,
formData.channelListings,
(a, b) => a.id === b.id
).removed?.map(removedChannel => removedChannel.id)
: [];
const initialIds = prevChannels.map(channel => channel.id);
const modifiedIds = formData.channelListings.map(channel => channel.id);
const idsDiff = arrayDiff(initialIds, modifiedIds);
return {
id,
@ -147,7 +142,7 @@ export const getSaleChannelsVariables = (
channelId: channel.id,
discountValue: channel.discountValue
})) || [],
removeChannels
removeChannels: idsDiff.removed
}
};
};

View file

@ -40,13 +40,13 @@ import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPage
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
import { FetchMoreProps, ReorderEvent } from "@saleor/types";
import { arrayDiff } from "@saleor/utils/arrays";
import handleFormSubmit from "@saleor/utils/handlers/handleFormSubmit";
import createMultiAutocompleteSelectHandler from "@saleor/utils/handlers/multiAutocompleteSelectChangeHandler";
import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler";
import getMetadata from "@saleor/utils/metadata/getMetadata";
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
import useRichText from "@saleor/utils/richText/useRichText";
import { diff } from "fast-array-diff";
import React from "react";
import { ProductStockFormsetData, ProductStockInput } from "../ProductStocks";
@ -180,7 +180,7 @@ const getStocksData = (
const dataStocks = stocks.map(stock => stock.id);
const variantStocks =
product?.variants[0]?.stocks.map(stock => stock.warehouse.id) || [];
const stockDiff = diff(variantStocks, dataStocks);
const stockDiff = arrayDiff(variantStocks, dataStocks);
return {
addStocks: stocks.filter(stock =>

View file

@ -30,10 +30,10 @@ import { SearchPages_search_edges_node } from "@saleor/searches/types/SearchPage
import { SearchProducts_search_edges_node } from "@saleor/searches/types/SearchProducts";
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
import { FetchMoreProps, ReorderEvent } from "@saleor/types";
import { arrayDiff } from "@saleor/utils/arrays";
import { mapMetadataItemToInput } from "@saleor/utils/maps";
import getMetadata from "@saleor/utils/metadata/getMetadata";
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
import { diff } from "fast-array-diff";
import React from "react";
import handleFormSubmit from "../../../utils/handlers/handleFormSubmit";
@ -206,7 +206,7 @@ function useProductVariantUpdateForm(
const dataStocks = stocks.data.map(stock => stock.id);
const variantStocks = variant?.stocks.map(stock => stock.warehouse.id) || [];
const stockDiff = diff(variantStocks, dataStocks);
const stockDiff = arrayDiff(variantStocks, dataStocks);
const addStocks = stocks.data.filter(stock =>
stockDiff.added.some(addedStock => addedStock === stock.id)

View file

@ -15,7 +15,7 @@ import { SimpleProductUpdate } from "@saleor/products/types/SimpleProductUpdate"
import { mapFormsetStockToStockInput } from "@saleor/products/utils/data";
import { getAvailabilityVariables } from "@saleor/products/utils/handlers";
import { ProductChannelListingAddInput } from "@saleor/types/globalTypes";
import { diff } from "fast-array-diff";
import { arrayDiff } from "@saleor/utils/arrays";
import isEqual from "lodash/isEqual";
import { ChannelsWithVariantsData, ChannelWithVariantData } from "../types";
@ -70,7 +70,7 @@ export const getChannelListingUpdateInputFromData = (
basicChannelData: ChannelData
) => ({
...getChannelListingBaseInputData(basicChannelData),
addVariants: diff(initialSelectedVariantsIds, variantsIdsToAdd).added,
addVariants: arrayDiff(initialSelectedVariantsIds, variantsIdsToAdd).added,
removeVariants: variantsIdsToRemove
});
@ -164,10 +164,11 @@ export const getSimpleChannelsVariables = (
product: ProductDetails_product
) => {
const productChannels = createSortedChannelsDataFromProduct(product);
const diffChannels = diff(
productChannels,
data.channelListings,
(a, b) => a.id === b.id
const existingChannelIDs = productChannels.map(channel => channel.id);
const modifiedChannelIDs = data.channelListings.map(channel => channel.id);
const removedChannelIDs = existingChannelIDs.filter(
x => !modifiedChannelIDs.includes(x)
);
return {
@ -175,9 +176,7 @@ export const getSimpleChannelsVariables = (
id: product.id,
input: {
updateChannels: getAvailabilityVariables(data.channelListings),
removeChannels: diffChannels.removed?.map(
removedChannel => removedChannel.id
)
removeChannels: removedChannelIDs
}
}
};

View file

@ -19,6 +19,7 @@ import {
useShippingZoneDelete,
useShippingZoneUpdate
} from "@saleor/shipping/mutations";
import { arrayDiff } from "@saleor/utils/arrays";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler";
import { mapEdgesToItems } from "@saleor/utils/maps";
@ -27,7 +28,6 @@ import {
usePrivateMetadataUpdate
} from "@saleor/utils/metadata/updateMetadata";
import { useWarehouseCreate } from "@saleor/warehouses/mutations";
import { diff } from "fast-array-diff";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
@ -133,12 +133,12 @@ const ShippingZoneDetails: React.FC<ShippingZoneDetailsProps> = ({
const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
const updateData = async (submitData: FormData) => {
const warehouseDiff = diff(
const warehouseDiff = arrayDiff(
data.shippingZone.warehouses.map(warehouse => warehouse.id),
submitData.warehouses
);
const channelsDiff = diff(
const channelsDiff = arrayDiff(
data.shippingZone.channels.map(channel => channel.id),
submitData.channels
);

View file

@ -0,0 +1,55 @@
import { arrayDiff } from "./arrays";
const fruits = ["apple", "orange", "strawberry"];
const vegetables = ["potato", "onion"];
describe("Validate diff results", () => {
it("Empty arrays", () => {
const diff = arrayDiff([], []);
expect(diff).toStrictEqual({ added: [], removed: [], common: [] });
});
it("Compare array with itself", () => {
const diff = arrayDiff(fruits, fruits);
expect(diff).toStrictEqual({ added: [], removed: [], common: fruits });
});
it("Added elements to empty", () => {
const diff = arrayDiff([], vegetables);
expect(diff).toStrictEqual({
added: vegetables,
removed: [],
common: []
});
});
it("Added elements to populated array", () => {
const diff = arrayDiff(fruits, [...fruits, ...vegetables]);
expect(diff).toStrictEqual({
added: vegetables,
removed: [],
common: fruits
});
});
it("Removed elements", () => {
const diff = arrayDiff([...fruits, ...vegetables], fruits);
expect(diff).toStrictEqual({
added: [],
removed: vegetables,
common: fruits
});
});
it("Added, removed, and common elements", () => {
const before = ["a", "b", "c", "d"];
const after = ["b", "e", "a", "t"];
const diff = arrayDiff(before, after);
expect(diff).toStrictEqual({
added: ["e", "t"],
removed: ["c", "d"],
common: ["a", "b"]
});
});
});

View file

@ -0,0 +1,8 @@
import difference from "lodash/difference";
import intersection from "lodash/intersection";
export const arrayDiff = (before: string[], after: string[]) => ({
added: difference(after, before),
removed: difference(before, after),
common: intersection(before, after)
});

View file

@ -0,0 +1 @@
export * from "./arrays";

View file

@ -1,7 +1,7 @@
import { MetadataFormData } from "@saleor/components/Metadata/types";
import { MetadataErrorFragment } from "@saleor/fragments/types/MetadataErrorFragment";
import { MetadataInput } from "@saleor/types/globalTypes";
import { diff } from "fast-array-diff";
import { arrayDiff } from "@saleor/utils/arrays";
import { MutationFetchResult } from "react-apollo";
import {
@ -40,16 +40,15 @@ function createMetadataUpdateHandler<TData extends MetadataFormData, TError>(
if (errors.length === 0) {
if (data.metadata) {
const metaDiff = diff(
initial.metadata,
data.metadata,
(a, b) => a.key === b.key
);
const initialKeys = initial.metadata.map(m => m.key);
const modifiedKeys = data.metadata.map(m => m.key);
const keyDiff = arrayDiff(initialKeys, modifiedKeys);
const updateMetaResult = await updateMetadata({
id: initial.id,
input: data.metadata,
keysToDelete: metaDiff.removed.map(meta => meta.key)
keysToDelete: keyDiff.removed
});
const updateMetaErrors = [
...(updateMetaResult.data.deleteMetadata.errors || []),
@ -62,16 +61,15 @@ function createMetadataUpdateHandler<TData extends MetadataFormData, TError>(
}
if (data.privateMetadata) {
const privateMetaDiff = diff(
initial.privateMetadata,
data.privateMetadata,
(a, b) => a.key === b.key
);
const initialKeys = initial.privateMetadata.map(m => m.key);
const modifiedKeys = data.privateMetadata.map(m => m.key);
const keyDiff = arrayDiff(initialKeys, modifiedKeys);
const updatePrivateMetaResult = await updatePrivateMetadata({
id: initial.id,
input: data.privateMetadata,
keysToDelete: privateMetaDiff.removed.map(meta => meta.key)
keysToDelete: keyDiff.removed
});
const updatePrivateMetaErrors = [