Skip to content

Commit

Permalink
#4128 category and collections columns (#4499)
Browse files Browse the repository at this point in the history
* Add Category and Collections columns

* Fix typescript

* Add changelog

* Make new columns data fetching conditional

---------

Co-authored-by: Paweł Chyła <chyla1988@gmail.com>
Co-authored-by: Patryk Andrzejewski <vox3r69@gmail.com>
  • Loading branch information
3 people authored Dec 1, 2023
1 parent 8eef741 commit 8766b21
Show file tree
Hide file tree
Showing 11 changed files with 160 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/pink-hornets-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---

Add Category and Collections columns to the product list datagrid.
8 changes: 8 additions & 0 deletions locale/defaultMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1654,6 +1654,10 @@
"context": "apps section name",
"string": "Apps"
},
"9qKFTA": {
"context": "Product category",
"string": "Category"
},
"9scTQ0": {
"context": "section header",
"string": "Product Attributes"
Expand Down Expand Up @@ -6670,6 +6674,10 @@
"context": "channel name",
"string": "Channel Name"
},
"j08fR9": {
"context": "Product collections",
"string": "Collections"
},
"j0ugM4": {
"context": "Manage and Update your warehouse information",
"string": "Exchange Rates"
Expand Down
4 changes: 3 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export type ProductListColumns =
| "description"
| "availability"
| "price"
| "date";
| "date"
| "productCategory"
| "productCollections";

export interface AppListViewSettings {
[ListViews.APPS_LIST]: ListSettings;
Expand Down
8 changes: 8 additions & 0 deletions src/fragments/products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ export const productFragment = gql`
name
hasVariants
}
category @include(if: $includeCategories) {
id
name
}
collections @include(if: $includeCollections) {
id
name
}
channelListings {
...ChannelListingProductWithoutPricing
pricing @include(if: $hasChannel) {
Expand Down
12 changes: 11 additions & 1 deletion src/graphql/hooks.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2371,6 +2371,14 @@ export const ProductWithChannelListingsFragmentDoc = gql`
name
hasVariants
}
category @include(if: $includeCategories) {
id
name
}
collections @include(if: $includeCollections) {
id
name
}
channelListings {
...ChannelListingProductWithoutPricing
pricing @include(if: $hasChannel) {
Expand Down Expand Up @@ -14213,7 +14221,7 @@ export type InitialProductFilterProductTypesQueryHookResult = ReturnType<typeof
export type InitialProductFilterProductTypesLazyQueryHookResult = ReturnType<typeof useInitialProductFilterProductTypesLazyQuery>;
export type InitialProductFilterProductTypesQueryResult = Apollo.QueryResult<Types.InitialProductFilterProductTypesQuery, Types.InitialProductFilterProductTypesQueryVariables>;
export const ProductListDocument = gql`
query ProductList($first: Int, $after: String, $last: Int, $before: String, $filter: ProductFilterInput, $search: String, $where: ProductWhereInput, $channel: String, $sort: ProductOrder, $hasChannel: Boolean!) {
query ProductList($first: Int, $after: String, $last: Int, $before: String, $filter: ProductFilterInput, $search: String, $where: ProductWhereInput, $channel: String, $sort: ProductOrder, $hasChannel: Boolean!, $includeCategories: Boolean!, $includeCollections: Boolean!) {
products(
before: $before
after: $after
Expand Down Expand Up @@ -14269,6 +14277,8 @@ ${ProductListAttributeFragmentDoc}`;
* channel: // value for 'channel'
* sort: // value for 'sort'
* hasChannel: // value for 'hasChannel'
* includeCategories: // value for 'includeCategories'
* includeCollections: // value for 'includeCollections'
* },
* });
*/
Expand Down
6 changes: 4 additions & 2 deletions src/graphql/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10029,7 +10029,7 @@ export type ChannelListingProductFragment = { __typename: 'ProductChannelListing

export type ChannelListingProductVariantFragment = { __typename: 'ProductVariantChannelListing', id: string, channel: { __typename: 'Channel', id: string, name: string, currencyCode: string }, price: { __typename: 'Money', amount: number, currency: string } | null, costPrice: { __typename: 'Money', amount: number, currency: string } | null, preorderThreshold: { __typename: 'PreorderThreshold', quantity: number | null, soldUnits: number } | null };

export type ProductWithChannelListingsFragment = { __typename: 'Product', id: string, name: string, thumbnail: { __typename: 'Image', url: string } | null, productType: { __typename: 'ProductType', id: string, name: string, hasVariants: boolean }, channelListings: Array<{ __typename: 'ProductChannelListing', isPublished: boolean, publicationDate: any | null, isAvailableForPurchase: boolean | null, availableForPurchase: any | null, visibleInListings: boolean, pricing?: { __typename: 'ProductPricingInfo', priceRange: { __typename: 'TaxedMoneyRange', start: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null, stop: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null } | null } | null, channel: { __typename: 'Channel', id: string, name: string, currencyCode: string } }> | null };
export type ProductWithChannelListingsFragment = { __typename: 'Product', id: string, name: string, thumbnail: { __typename: 'Image', url: string } | null, productType: { __typename: 'ProductType', id: string, name: string, hasVariants: boolean }, category?: { __typename: 'Category', id: string, name: string } | null, collections?: Array<{ __typename: 'Collection', id: string, name: string }> | null, channelListings: Array<{ __typename: 'ProductChannelListing', isPublished: boolean, publicationDate: any | null, isAvailableForPurchase: boolean | null, availableForPurchase: any | null, visibleInListings: boolean, pricing?: { __typename: 'ProductPricingInfo', priceRange: { __typename: 'TaxedMoneyRange', start: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null, stop: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null } | null } | null, channel: { __typename: 'Channel', id: string, name: string, currencyCode: string } }> | null };

export type ProductVariantAttributesFragment = { __typename: 'Product', id: string, attributes: Array<{ __typename: 'SelectedAttribute', attribute: { __typename: 'Attribute', id: string, slug: string | null, name: string | null, inputType: AttributeInputTypeEnum | null, entityType: AttributeEntityTypeEnum | null, valueRequired: boolean, unit: MeasurementUnitsEnum | null, choices: { __typename: 'AttributeValueCountableConnection', pageInfo: { __typename: 'PageInfo', endCursor: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor: string | null }, edges: Array<{ __typename: 'AttributeValueCountableEdge', cursor: string, node: { __typename: 'AttributeValue', plainText: string | null, richText: any | null, id: string, name: string | null, slug: string | null, reference: string | null, boolean: boolean | null, date: any | null, dateTime: any | null, value: string | null, file: { __typename: 'File', url: string, contentType: string | null } | null } }> } | null }, values: Array<{ __typename: 'AttributeValue', plainText: string | null, richText: any | null, id: string, name: string | null, slug: string | null, reference: string | null, boolean: boolean | null, date: any | null, dateTime: any | null, value: string | null, file: { __typename: 'File', url: string, contentType: string | null } | null }> }>, productType: { __typename: 'ProductType', id: string, variantAttributes: Array<{ __typename: 'Attribute', id: string, name: string | null, slug: string | null, inputType: AttributeInputTypeEnum | null, entityType: AttributeEntityTypeEnum | null, valueRequired: boolean, unit: MeasurementUnitsEnum | null, choices: { __typename: 'AttributeValueCountableConnection', pageInfo: { __typename: 'PageInfo', endCursor: string | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor: string | null }, edges: Array<{ __typename: 'AttributeValueCountableEdge', cursor: string, node: { __typename: 'AttributeValue', plainText: string | null, richText: any | null, id: string, name: string | null, slug: string | null, reference: string | null, boolean: boolean | null, date: any | null, dateTime: any | null, value: string | null, file: { __typename: 'File', url: string, contentType: string | null } | null } }> } | null }> | null }, channelListings: Array<{ __typename: 'ProductChannelListing', channel: { __typename: 'Channel', id: string, name: string, currencyCode: string } }> | null };

Expand Down Expand Up @@ -11303,10 +11303,12 @@ export type ProductListQueryVariables = Exact<{
channel?: InputMaybe<Scalars['String']>;
sort?: InputMaybe<ProductOrder>;
hasChannel: Scalars['Boolean'];
includeCategories: Scalars['Boolean'];
includeCollections: Scalars['Boolean'];
}>;


export type ProductListQuery = { __typename: 'Query', products: { __typename: 'ProductCountableConnection', totalCount: number | null, edges: Array<{ __typename: 'ProductCountableEdge', node: { __typename: 'Product', updatedAt: any, description: any | null, id: string, name: string, attributes: Array<{ __typename: 'SelectedAttribute', attribute: { __typename: 'Attribute', id: string }, values: Array<{ __typename: 'AttributeValue', id: string, name: string | null, slug: string | null, reference: string | null, boolean: boolean | null, date: any | null, dateTime: any | null, value: string | null, file: { __typename: 'File', url: string, contentType: string | null } | null }> }>, thumbnail: { __typename: 'Image', url: string } | null, productType: { __typename: 'ProductType', id: string, name: string, hasVariants: boolean }, channelListings: Array<{ __typename: 'ProductChannelListing', isPublished: boolean, publicationDate: any | null, isAvailableForPurchase: boolean | null, availableForPurchase: any | null, visibleInListings: boolean, pricing?: { __typename: 'ProductPricingInfo', priceRange: { __typename: 'TaxedMoneyRange', start: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null, stop: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null } | null } | null, channel: { __typename: 'Channel', id: string, name: string, currencyCode: string } }> | null } }>, pageInfo: { __typename: 'PageInfo', hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string | null, endCursor: string | null } } | null };
export type ProductListQuery = { __typename: 'Query', products: { __typename: 'ProductCountableConnection', totalCount: number | null, edges: Array<{ __typename: 'ProductCountableEdge', node: { __typename: 'Product', updatedAt: any, description: any | null, id: string, name: string, attributes: Array<{ __typename: 'SelectedAttribute', attribute: { __typename: 'Attribute', id: string }, values: Array<{ __typename: 'AttributeValue', id: string, name: string | null, slug: string | null, reference: string | null, boolean: boolean | null, date: any | null, dateTime: any | null, value: string | null, file: { __typename: 'File', url: string, contentType: string | null } | null }> }>, thumbnail: { __typename: 'Image', url: string } | null, productType: { __typename: 'ProductType', id: string, name: string, hasVariants: boolean }, category?: { __typename: 'Category', id: string, name: string } | null, collections?: Array<{ __typename: 'Collection', id: string, name: string }> | null, channelListings: Array<{ __typename: 'ProductChannelListing', isPublished: boolean, publicationDate: any | null, isAvailableForPurchase: boolean | null, availableForPurchase: any | null, visibleInListings: boolean, pricing?: { __typename: 'ProductPricingInfo', priceRange: { __typename: 'TaxedMoneyRange', start: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null, stop: { __typename: 'TaxedMoney', net: { __typename: 'Money', amount: number, currency: string } } | null } | null } | null, channel: { __typename: 'Channel', id: string, name: string, currencyCode: string } }> | null } }>, pageInfo: { __typename: 'PageInfo', hasPreviousPage: boolean, hasNextPage: boolean, startCursor: string | null, endCursor: string | null } } | null };

export type ProductCountQueryVariables = Exact<{
filter?: InputMaybe<ProductFilterInput>;
Expand Down
60 changes: 60 additions & 0 deletions src/products/components/ProductListDatagrid/datagrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
pillCell,
readonlyTextCell,
statusCell,
tagsCell,
thumbnailCell,
} from "@dashboard/components/Datagrid/customCells/cells";
import {
Expand Down Expand Up @@ -78,6 +79,16 @@ export const productListStaticColumnAdapter = (
title: intl.formatMessage(columnsMessages.price),
width: 250,
},
{
id: "productCategory",
title: intl.formatMessage(columnsMessages.category),
width: 200,
},
{
id: "productCollections",
title: intl.formatMessage(columnsMessages.collections),
width: 300,
},
].map(column => ({
...column,
icon: getColumnSortDirectionIcon(sort, column.id),
Expand Down Expand Up @@ -203,6 +214,10 @@ export function createGetCellContent({
return getPriceCellContent(channel);
case "date":
return getDateCellContent(rowData);
case "productCategory":
return getCategoryCellContent(theme, rowData);
case "productCollections":
return getCollectionsCellContent(theme, rowData);
}

if (columnId.startsWith("attribute")) {
Expand Down Expand Up @@ -231,6 +246,51 @@ function getProductTypeCellContent(
return pillCell(rowData.productType?.name, color);
}

function getCategoryCellContent(
theme: DefaultTheme,
rowData: RelayToFlat<ProductListQuery["products"]>[number],
) {
if (!rowData.category) {
return readonlyTextCell("-");
}

const hue = stringToHue(rowData.category?.name);
const color =
theme === "defaultDark"
? hueToPillColorDark(hue)
: hueToPillColorLight(hue);
return pillCell(rowData.category?.name, color);
}

function getCollectionsCellContent(
theme: DefaultTheme,
rowData: RelayToFlat<ProductListQuery["products"]>[number],
) {
if (rowData.collections === undefined || rowData.collections.length === 0) {
return readonlyTextCell("-");
}

const tags = rowData.collections.map(collection => {
const hue = stringToHue(collection.name);
const color =
theme === "defaultDark"
? hueToPillColorDark(hue)
: hueToPillColorLight(hue);
return {
tag: collection.name,
color: color.base,
};
});
return tagsCell(
tags,
tags.map(tag => tag.tag),
{
readonly: true,
allowOverlay: false,
},
);
}

function getAvailabilityCellContent(
rowData: RelayToFlat<ProductListQuery["products"]>[number],
intl: IntlShape,
Expand Down
10 changes: 10 additions & 0 deletions src/products/components/ProductListDatagrid/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ export const columnsMessages = defineMessages({
defaultMessage: "Last updated",
description: "product updated at",
},
category: {
id: "9qKFTA",
defaultMessage: "Category",
description: "Product category",
},
collections: {
id: "j08fR9",
defaultMessage: "Collections",
description: "Product collections",
},
});

export const categoryMetaGroups = defineMessages({
Expand Down
40 changes: 40 additions & 0 deletions src/products/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -1416,6 +1418,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -1509,6 +1513,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -1624,6 +1630,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -1739,6 +1747,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -1855,6 +1865,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -1970,6 +1982,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2085,6 +2099,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2200,6 +2216,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2315,6 +2333,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2430,6 +2450,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2545,6 +2567,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2660,6 +2684,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2775,6 +2801,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -2890,6 +2918,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -3005,6 +3035,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -3120,6 +3152,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -3235,6 +3269,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -3350,6 +3386,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
{
__typename: "Product",
Expand Down Expand Up @@ -3465,6 +3503,8 @@ export const products = (
__typename: "Image",
url: placeholderImage,
},
category: null,
collections: [],
},
];

Expand Down
Loading

0 comments on commit 8766b21

Please sign in to comment.