From 1eca4dd0509a2e4d32304ab35973de204d343766 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 26 Sep 2019 12:14:07 +0200 Subject: [PATCH 1/3] Allow sorting products by attribute --- schema.graphql | 391 +++++++++++++++++- src/misc.ts | 3 + .../components/ProductList/ProductList.tsx | 48 ++- .../ProductListPage/ProductListPage.tsx | 1 + src/products/urls.ts | 16 +- .../views/ProductList/ProductList.tsx | 20 +- src/products/views/ProductList/sort.ts | 8 + src/types.ts | 2 +- src/types/globalTypes.ts | 3 +- 9 files changed, 454 insertions(+), 38 deletions(-) diff --git a/schema.graphql b/schema.graphql index 8c8d128f4..05bbd4e1a 100644 --- a/schema.graphql +++ b/schema.graphql @@ -6,26 +6,57 @@ schema { type AccountAddressCreate { errors: [Error!] user: User + accountErrors: [AccountError!] address: Address } type AccountAddressDelete { errors: [Error!] user: User + accountErrors: [AccountError!] address: Address } type AccountAddressUpdate { errors: [Error!] user: User + accountErrors: [AccountError!] address: Address } type AccountDelete { errors: [Error!] + accountErrors: [AccountError!] user: User } +type AccountError { + field: String + message: String + code: AccountErrorCode +} + +enum AccountErrorCode { + ACTIVATE_OWN_ACCOUNT + ACTIVATE_SUPERUSER_ACCOUNT + DEACTIVATE_OWN_ACCOUNT + DEACTIVATE_SUPERUSER_ACCOUNT + DELETE_NON_STAFF_USER + DELETE_OWN_ACCOUNT + DELETE_STAFF_ACCOUNT + DELETE_SUPERUSER_ACCOUNT + GRAPHQL_ERROR + INVALID + INVALID_PASSWORD + NOT_FOUND + PASSWORD_ENTIRELY_NUMERIC + PASSWORD_TOO_COMMON + PASSWORD_TOO_SHORT + PASSWORD_TOO_SIMILAR + REQUIRED + UNIQUE +} + input AccountInput { firstName: String lastName: String @@ -35,6 +66,7 @@ input AccountInput { type AccountRegister { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -45,15 +77,18 @@ input AccountRegisterInput { type AccountRequestDeletion { errors: [Error!] + accountErrors: [AccountError!] } type AccountSetDefaultAddress { errors: [Error!] user: User + accountErrors: [AccountError!] } type AccountUpdate { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -77,12 +112,14 @@ type Address implements Node { type AddressCreate { errors: [Error!] user: User + accountErrors: [AccountError!] address: Address } type AddressDelete { errors: [Error!] user: User + accountErrors: [AccountError!] address: Address } @@ -103,6 +140,7 @@ input AddressInput { type AddressSetDefault { errors: [Error!] user: User + accountErrors: [AccountError!] } enum AddressTypeEnum { @@ -113,6 +151,7 @@ enum AddressTypeEnum { type AddressUpdate { errors: [Error!] user: User + accountErrors: [AccountError!] address: Address } @@ -139,6 +178,7 @@ type AddressValidationData { type AssignNavigation { errors: [Error!] menu: Menu + menuErrors: [MenuError!] } type Attribute implements Node { @@ -163,6 +203,7 @@ type Attribute implements Node { type AttributeAssign { errors: [Error!] productType: ProductType + productErrors: [ProductError!] } input AttributeAssignInput { @@ -173,15 +214,18 @@ input AttributeAssignInput { type AttributeBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type AttributeClearMeta { errors: [Error!] + productErrors: [ProductError!] attribute: Attribute } type AttributeClearPrivateMeta { errors: [Error!] + productErrors: [ProductError!] attribute: Attribute } @@ -199,6 +243,7 @@ type AttributeCountableEdge { type AttributeCreate { errors: [Error!] attribute: Attribute + productErrors: [ProductError!] } input AttributeCreateInput { @@ -217,6 +262,7 @@ input AttributeCreateInput { type AttributeDelete { errors: [Error!] + productErrors: [ProductError!] attribute: Attribute } @@ -244,6 +290,7 @@ enum AttributeInputTypeEnum { type AttributeReorderValues { errors: [Error!] attribute: Attribute + productErrors: [ProductError!] } scalar AttributeScalar @@ -286,11 +333,13 @@ enum AttributeTypeEnum { type AttributeUnassign { errors: [Error!] productType: ProductType + productErrors: [ProductError!] } type AttributeUpdate { errors: [Error!] attribute: Attribute + productErrors: [ProductError!] } input AttributeUpdateInput { @@ -309,11 +358,13 @@ input AttributeUpdateInput { type AttributeUpdateMeta { errors: [Error!] + productErrors: [ProductError!] attribute: Attribute } type AttributeUpdatePrivateMeta { errors: [Error!] + productErrors: [ProductError!] attribute: Attribute } @@ -329,11 +380,13 @@ type AttributeValue implements Node { type AttributeValueBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type AttributeValueCreate { errors: [Error!] attribute: Attribute + productErrors: [ProductError!] attributeValue: AttributeValue } @@ -344,6 +397,7 @@ input AttributeValueCreateInput { type AttributeValueDelete { errors: [Error!] attribute: Attribute + productErrors: [ProductError!] attributeValue: AttributeValue } @@ -374,6 +428,7 @@ enum AttributeValueType { type AttributeValueUpdate { errors: [Error!] attribute: Attribute + productErrors: [ProductError!] attributeValue: AttributeValue } @@ -386,12 +441,14 @@ type AuthorizationKeyAdd { errors: [Error!] authorizationKey: AuthorizationKey shop: Shop + shopErrors: [ShopError!] } type AuthorizationKeyDelete { errors: [Error!] authorizationKey: AuthorizationKey shop: Shop + shopErrors: [ShopError!] } input AuthorizationKeyInput { @@ -433,15 +490,18 @@ type Category implements Node { type CategoryBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type CategoryClearMeta { errors: [Error!] + productErrors: [ProductError!] category: Category } type CategoryClearPrivateMeta { errors: [Error!] + productErrors: [ProductError!] category: Category } @@ -458,11 +518,13 @@ type CategoryCountableEdge { type CategoryCreate { errors: [Error!] + productErrors: [ProductError!] category: Category } type CategoryDelete { errors: [Error!] + productErrors: [ProductError!] category: Category } @@ -497,16 +559,19 @@ type CategoryTranslation implements Node { type CategoryUpdate { errors: [Error!] + productErrors: [ProductError!] category: Category } type CategoryUpdateMeta { errors: [Error!] + productErrors: [ProductError!] category: Category } type CategoryUpdatePrivateMeta { errors: [Error!] + productErrors: [ProductError!] category: Category } @@ -542,26 +607,31 @@ type Checkout implements Node { type CheckoutAddPromoCode { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutBillingAddressUpdate { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutClearStoredMeta { errors: [Error!] + checkoutErrors: [CheckoutError!] checkout: Checkout } type CheckoutClearStoredPrivateMeta { errors: [Error!] + checkoutErrors: [CheckoutError!] checkout: Checkout } type CheckoutComplete { errors: [Error!] order: Order + checkoutErrors: [CheckoutError!] } type CheckoutCountableConnection { @@ -578,6 +648,7 @@ type CheckoutCountableEdge { type CheckoutCreate { errors: [Error!] created: Boolean + checkoutErrors: [CheckoutError!] checkout: Checkout } @@ -591,16 +662,46 @@ input CheckoutCreateInput { type CheckoutCustomerAttach { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutCustomerDetach { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutEmailUpdate { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] +} + +type CheckoutError { + field: String + message: String + code: CheckoutErrorCode +} + +enum CheckoutErrorCode { + BILLING_ADDRESS_NOT_SET + CHECKOUT_NOT_FULLY_PAID + GRAPHQL_ERROR + INSUFFICIENT_STOCK + INVALID + INVALID_SHIPPING_METHOD + NOT_FOUND + PAYMENT_ERROR + QUANTITY_GREATER_THAN_LIMIT + REQUIRED + SHIPPING_ADDRESS_NOT_SET + SHIPPING_METHOD_NOT_APPLICABLE + SHIPPING_METHOD_NOT_SET + SHIPPING_NOT_REQUIRED + TAX_ERROR + UNIQUE + VOUCHER_NOT_APPLICABLE + ZERO_QUANTITY } type CheckoutLine implements Node { @@ -625,6 +726,7 @@ type CheckoutLineCountableEdge { type CheckoutLineDelete { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } input CheckoutLineInput { @@ -635,47 +737,56 @@ input CheckoutLineInput { type CheckoutLinesAdd { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutLinesUpdate { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutPaymentCreate { errors: [Error!] checkout: Checkout payment: Payment + paymentErrors: [PaymentError!] } type CheckoutRemovePromoCode { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutShippingAddressUpdate { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutShippingMethodUpdate { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type CheckoutUpdateMeta { errors: [Error!] + checkoutErrors: [CheckoutError!] checkout: Checkout } type CheckoutUpdatePrivateMeta { errors: [Error!] + checkoutErrors: [CheckoutError!] checkout: Checkout } type CheckoutUpdateVoucher { errors: [Error!] checkout: Checkout + checkoutErrors: [CheckoutError!] } type ChoiceValue { @@ -703,25 +814,30 @@ type Collection implements Node { type CollectionAddProducts { errors: [Error!] collection: Collection + productErrors: [ProductError!] } type CollectionBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type CollectionBulkPublish { errors: [Error!] count: Int! + productErrors: [ProductError!] } type CollectionClearMeta { errors: [Error!] + productErrors: [ProductError!] collection: Collection } type CollectionClearPrivateMeta { errors: [Error!] + productErrors: [ProductError!] collection: Collection } @@ -738,6 +854,7 @@ type CollectionCountableEdge { type CollectionCreate { errors: [Error!] + productErrors: [ProductError!] collection: Collection } @@ -756,6 +873,7 @@ input CollectionCreateInput { type CollectionDelete { errors: [Error!] + productErrors: [ProductError!] collection: Collection } @@ -784,11 +902,13 @@ enum CollectionPublished { type CollectionRemoveProducts { errors: [Error!] collection: Collection + productErrors: [ProductError!] } type CollectionReorderProducts { errors: [Error!] collection: Collection + productErrors: [ProductError!] } type CollectionTranslate { @@ -808,16 +928,19 @@ type CollectionTranslation implements Node { type CollectionUpdate { errors: [Error!] + productErrors: [ProductError!] collection: Collection } type CollectionUpdateMeta { errors: [Error!] + productErrors: [ProductError!] collection: Collection } type CollectionUpdatePrivateMeta { errors: [Error!] + productErrors: [ProductError!] collection: Collection } @@ -1121,15 +1244,18 @@ type CustomerAddressCreate { type CustomerBulkDelete { errors: [Error!] count: Int! + accountErrors: [AccountError!] } type CustomerCreate { errors: [Error!] + accountErrors: [AccountError!] user: User } type CustomerDelete { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -1200,6 +1326,7 @@ type CustomerSetDefaultAddress { type CustomerUpdate { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -1247,11 +1374,13 @@ type DigitalContentCreate { errors: [Error!] variant: ProductVariant content: DigitalContent + productErrors: [ProductError!] } type DigitalContentDelete { errors: [Error!] variant: ProductVariant + productErrors: [ProductError!] } input DigitalContentInput { @@ -1265,6 +1394,7 @@ type DigitalContentUpdate { errors: [Error!] variant: ProductVariant content: DigitalContent + productErrors: [ProductError!] } input DigitalContentUploadInput { @@ -1286,6 +1416,7 @@ type DigitalContentUrl implements Node { type DigitalContentUrlCreate { errors: [Error!] + productErrors: [ProductError!] digitalContentUrl: DigitalContentUrl } @@ -1313,15 +1444,18 @@ type Domain { type DraftOrderBulkDelete { errors: [Error!] count: Int! + orderErrors: [OrderError!] } type DraftOrderComplete { errors: [Error!] order: Order + orderErrors: [OrderError!] } type DraftOrderCreate { errors: [Error!] + orderErrors: [OrderError!] order: Order } @@ -1338,6 +1472,7 @@ input DraftOrderCreateInput { type DraftOrderDelete { errors: [Error!] + orderErrors: [OrderError!] order: Order } @@ -1355,27 +1490,32 @@ type DraftOrderLineDelete { errors: [Error!] order: Order orderLine: OrderLine + orderErrors: [OrderError!] } type DraftOrderLineUpdate { errors: [Error!] order: Order + orderErrors: [OrderError!] orderLine: OrderLine } type DraftOrderLinesBulkDelete { errors: [Error!] count: Int! + orderErrors: [OrderError!] } type DraftOrderLinesCreate { errors: [Error!] order: Order orderLines: [OrderLine!] + orderErrors: [OrderError!] } type DraftOrderUpdate { errors: [Error!] + orderErrors: [OrderError!] order: Order } @@ -1384,6 +1524,21 @@ type Error { message: String } +type ExtensionsError { + field: String + message: String + code: ExtensionsErrorCode +} + +enum ExtensionsErrorCode { + GRAPHQL_ERROR + INVALID + PLUGIN_MISCONFIGURED + NOT_FOUND + REQUIRED + UNIQUE +} + type Fulfillment implements Node { id: ID! fulfillmentOrder: Int! @@ -1398,6 +1553,7 @@ type FulfillmentCancel { errors: [Error!] fulfillment: Fulfillment order: Order + orderErrors: [OrderError!] } input FulfillmentCancelInput { @@ -1408,6 +1564,7 @@ type FulfillmentCreate { errors: [Error!] fulfillment: Fulfillment order: Order + orderErrors: [OrderError!] } input FulfillmentCreateInput { @@ -1436,6 +1593,7 @@ type FulfillmentUpdateTracking { errors: [Error!] fulfillment: Fulfillment order: Order + orderErrors: [OrderError!] } input FulfillmentUpdateTrackingInput { @@ -1473,6 +1631,7 @@ type GiftCard implements Node { type GiftCardActivate { errors: [Error!] giftCard: GiftCard + giftCardErrors: [GiftCardError!] } type GiftCardCountableConnection { @@ -1488,6 +1647,7 @@ type GiftCardCountableEdge { type GiftCardCreate { errors: [Error!] + giftCardErrors: [GiftCardError!] giftCard: GiftCard } @@ -1502,10 +1662,27 @@ input GiftCardCreateInput { type GiftCardDeactivate { errors: [Error!] giftCard: GiftCard + giftCardErrors: [GiftCardError!] +} + +type GiftCardError { + field: String + message: String + code: GiftCardErrorCode +} + +enum GiftCardErrorCode { + ALREADY_EXISTS + GRAPHQL_ERROR + INVALID + NOT_FOUND + REQUIRED + UNIQUE } type GiftCardUpdate { errors: [Error!] + giftCardErrors: [GiftCardError!] giftCard: GiftCard } @@ -1519,6 +1696,7 @@ input GiftCardUpdateInput { type HomepageCollectionUpdate { errors: [Error!] shop: Shop + shopErrors: [ShopError!] } type Image { @@ -1603,6 +1781,7 @@ type Menu implements Node { type MenuBulkDelete { errors: [Error!] count: Int! + menuErrors: [MenuError!] } type MenuCountableConnection { @@ -1618,6 +1797,7 @@ type MenuCountableEdge { type MenuCreate { errors: [Error!] + menuErrors: [MenuError!] menu: Menu } @@ -1628,9 +1808,28 @@ input MenuCreateInput { type MenuDelete { errors: [Error!] + menuErrors: [MenuError!] menu: Menu } +type MenuError { + field: String + message: String + code: MenuErrorCode +} + +enum MenuErrorCode { + CANNOT_ASSIGN_NODE + GRAPHQL_ERROR + INVALID + INVALID_MENU_ITEM + NO_MENU_ITEM_PROVIDED + NOT_FOUND + REQUIRED + TOO_MANY_MENU_ITEMS + UNIQUE +} + input MenuFilterInput { search: String } @@ -1641,7 +1840,7 @@ input MenuInput { type MenuItem implements Node { id: ID! - sortOrder: Int + sortOrder: Int @deprecated(reason: "Will be dropped in 2.10 and is deprecated since 2.9: use the position in list instead and relative calculus to determine shift position.") menu: Menu! name: String! parent: MenuItem @@ -1657,6 +1856,7 @@ type MenuItem implements Node { type MenuItemBulkDelete { errors: [Error!] count: Int! + menuErrors: [MenuError!] } type MenuItemCountableConnection { @@ -1672,6 +1872,7 @@ type MenuItemCountableEdge { type MenuItemCreate { errors: [Error!] + menuErrors: [MenuError!] menuItem: MenuItem } @@ -1687,6 +1888,7 @@ input MenuItemCreateInput { type MenuItemDelete { errors: [Error!] + menuErrors: [MenuError!] menuItem: MenuItem } @@ -1705,6 +1907,7 @@ input MenuItemInput { type MenuItemMove { errors: [Error!] menu: Menu + menuErrors: [MenuError!] } input MenuItemMoveInput { @@ -1726,11 +1929,13 @@ type MenuItemTranslation implements Node { type MenuItemUpdate { errors: [Error!] + menuErrors: [MenuError!] menuItem: MenuItem } type MenuUpdate { errors: [Error!] + menuErrors: [MenuError!] menu: Menu } @@ -2072,6 +2277,7 @@ type OrderAddNote { errors: [Error!] order: Order event: OrderEvent + orderErrors: [OrderError!] } input OrderAddNoteInput { @@ -2081,16 +2287,19 @@ input OrderAddNoteInput { type OrderBulkCancel { errors: [Error!] count: Int! + orderErrors: [OrderError!] } type OrderCancel { errors: [Error!] order: Order + orderErrors: [OrderError!] } type OrderCapture { errors: [Error!] order: Order + orderErrors: [OrderError!] } type OrderCountableConnection { @@ -2115,6 +2324,34 @@ input OrderDraftFilterInput { search: String } +type OrderError { + field: String + message: String + code: OrderErrorCode +} + +enum OrderErrorCode { + CANNOT_CANCEL_FULFILLMENT + CANNOT_CANCEL_ORDER + CANNOT_DELETE + CANNOT_REFUND + CAPTURE_INACTIVE_PAYMENT + NOT_EDITABLE + FULFILL_ORDER_LINE + GRAPHQL_ERROR + INVALID + NOT_FOUND + ORDER_NO_SHIPPING_ADDRESS + PAYMENT_ERROR + PAYMENT_MISSING + REQUIRED + SHIPPING_METHOD_NOT_APPLICABLE + SHIPPING_METHOD_REQUIRED + UNIQUE + VOID_INACTIVE_PAYMENT + ZERO_QUANTITY +} + type OrderEvent implements Node { id: ID! date: DateTime @@ -2221,11 +2458,13 @@ input OrderLineInput { type OrderMarkAsPaid { errors: [Error!] order: Order + orderErrors: [OrderError!] } type OrderRefund { errors: [Error!] order: Order + orderErrors: [OrderError!] } enum OrderStatus { @@ -2247,6 +2486,7 @@ enum OrderStatusFilter { type OrderUpdate { errors: [Error!] + orderErrors: [OrderError!] order: Order } @@ -2259,6 +2499,7 @@ input OrderUpdateInput { type OrderUpdateShipping { errors: [Error!] order: Order + orderErrors: [OrderError!] } input OrderUpdateShippingInput { @@ -2268,6 +2509,7 @@ input OrderUpdateShippingInput { type OrderVoid { errors: [Error!] order: Order + orderErrors: [OrderError!] } type Page implements Node { @@ -2367,6 +2609,7 @@ type PageUpdate { type PasswordChange { errors: [Error!] user: User + accountErrors: [AccountError!] } type PasswordReset { @@ -2399,6 +2642,7 @@ type Payment implements Node { type PaymentCapture { errors: [Error!] payment: Payment + paymentErrors: [PaymentError!] } enum PaymentChargeStatusEnum { @@ -2420,6 +2664,23 @@ type PaymentCountableEdge { cursor: String! } +type PaymentError { + field: String + message: String + code: PaymentErrorCode +} + +enum PaymentErrorCode { + BILLING_ADDRESS_NOT_SET + GRAPHQL_ERROR + INVALID + NOT_FOUND + PARTIAL_PAYMENT_NOT_ALLOWED + PAYMENT_ERROR + REQUIRED + UNIQUE +} + input PaymentInput { gateway: GatewaysEnum! token: String! @@ -2430,11 +2691,13 @@ input PaymentInput { type PaymentRefund { errors: [Error!] payment: Payment + paymentErrors: [PaymentError!] } type PaymentSecureConfirm { errors: [Error!] payment: Payment + paymentErrors: [PaymentError!] } type PaymentSource { @@ -2445,6 +2708,7 @@ type PaymentSource { type PaymentVoid { errors: [Error!] payment: Payment + paymentErrors: [PaymentError!] } type PermissionDisplay { @@ -2496,6 +2760,7 @@ input PluginFilterInput { type PluginUpdate { errors: [Error!] plugin: Plugin + extensionsErrors: [ExtensionsError!] } input PluginUpdateInput { @@ -2547,20 +2812,24 @@ type Product implements Node { type ProductBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type ProductBulkPublish { errors: [Error!] count: Int! + productErrors: [ProductError!] } type ProductClearMeta { errors: [Error!] + productErrors: [ProductError!] product: Product } type ProductClearPrivateMeta { errors: [Error!] + productErrors: [ProductError!] product: Product } @@ -2577,6 +2846,7 @@ type ProductCountableEdge { type ProductCreate { errors: [Error!] + productErrors: [ProductError!] product: Product } @@ -2602,9 +2872,30 @@ input ProductCreateInput { type ProductDelete { errors: [Error!] + productErrors: [ProductError!] product: Product } +type ProductError { + field: String + message: String + code: ProductErrorCode +} + +enum ProductErrorCode { + ALREADY_EXISTS + ATTRIBUTE_ALREADY_ASSIGNED + ATTRIBUTE_CANNOT_BE_ASSIGNED + ATTRIBUTE_VARIANTS_DISABLED + GRAPHQL_ERROR + INVALID + NOT_PRODUCTS_IMAGE + NOT_FOUND + REQUIRED + UNIQUE + VARIANT_NO_DIGITAL_CONTENT +} + input ProductFilterInput { isPublished: Boolean collections: [ID] @@ -2627,12 +2918,14 @@ type ProductImage implements Node { type ProductImageBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type ProductImageCreate { errors: [Error!] product: Product image: ProductImage + productErrors: [ProductError!] } input ProductImageCreateInput { @@ -2645,18 +2938,21 @@ type ProductImageDelete { errors: [Error!] product: Product image: ProductImage + productErrors: [ProductError!] } type ProductImageReorder { errors: [Error!] product: Product images: [ProductImage] + productErrors: [ProductError!] } type ProductImageUpdate { errors: [Error!] product: Product image: ProductImage + productErrors: [ProductError!] } input ProductImageUpdateInput { @@ -2683,7 +2979,8 @@ input ProductInput { } input ProductOrder { - field: ProductOrderField! + field: ProductOrderField + attributeId: ID direction: OrderDirection! } @@ -2741,15 +3038,18 @@ type ProductType implements Node { type ProductTypeBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type ProductTypeClearMeta { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } type ProductTypeClearPrivateMeta { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } @@ -2771,11 +3071,13 @@ type ProductTypeCountableEdge { type ProductTypeCreate { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } type ProductTypeDelete { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } @@ -2804,35 +3106,42 @@ input ProductTypeInput { type ProductTypeReorderAttributes { errors: [Error!] productType: ProductType + productErrors: [ProductError!] } type ProductTypeUpdate { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } type ProductTypeUpdateMeta { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } type ProductTypeUpdatePrivateMeta { errors: [Error!] + productErrors: [ProductError!] productType: ProductType } type ProductUpdate { errors: [Error!] + productErrors: [ProductError!] product: Product } type ProductUpdateMeta { errors: [Error!] + productErrors: [ProductError!] product: Product } type ProductUpdatePrivateMeta { errors: [Error!] + productErrors: [ProductError!] product: Product } @@ -2866,15 +3175,18 @@ type ProductVariant implements Node { type ProductVariantBulkDelete { errors: [Error!] count: Int! + productErrors: [ProductError!] } type ProductVariantClearMeta { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } type ProductVariantClearPrivateMeta { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } @@ -2891,6 +3203,7 @@ type ProductVariantCountableEdge { type ProductVariantCreate { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } @@ -2907,6 +3220,7 @@ input ProductVariantCreateInput { type ProductVariantDelete { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } @@ -2933,16 +3247,19 @@ type ProductVariantTranslation implements Node { type ProductVariantUpdate { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } type ProductVariantUpdateMeta { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } type ProductVariantUpdatePrivateMeta { errors: [Error!] + productErrors: [ProductError!] productVariant: ProductVariant } @@ -2952,7 +3269,7 @@ type Query { shippingZone(id: ID!): ShippingZone shippingZones(before: String, after: String, first: Int, last: Int): ShippingZoneCountableConnection digitalContent(id: ID!): DigitalContent - digitalContents(query: String, level: Int, before: String, after: String, first: Int, last: Int): DigitalContentCountableConnection + digitalContents(before: String, after: String, first: Int, last: Int): DigitalContentCountableConnection attributes(query: String, inCategory: ID, inCollection: ID, filter: AttributeFilterInput, sortBy: AttributeSortingInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection attribute(id: ID!): Attribute categories(query: String, filter: CategoryFilterInput, level: Int, before: String, after: String, first: Int, last: Int): CategoryCountableConnection @@ -2966,7 +3283,7 @@ type Query { productVariant(id: ID!): ProductVariant productVariants(ids: [ID], before: String, after: String, first: Int, last: Int): ProductVariantCountableConnection reportProductSales(period: ReportingPeriod!, before: String, after: String, first: Int, last: Int): ProductVariantCountableConnection - payment(id: ID): Payment + payment(id: ID!): Payment payments(before: String, after: String, first: Int, last: Int): PaymentCountableConnection paymentClientToken(gateway: GatewaysEnum): String page(id: ID, slug: String): Page @@ -2976,7 +3293,7 @@ type Query { orders(filter: OrderFilterInput, query: String, created: ReportingPeriod, status: OrderStatusFilter, before: String, after: String, first: Int, last: Int): OrderCountableConnection draftOrders(filter: OrderDraftFilterInput, query: String, created: ReportingPeriod, before: String, after: String, first: Int, last: Int): OrderCountableConnection ordersTotal(period: ReportingPeriod): TaxedMoney - orderByToken(token: String!): Order + orderByToken(token: UUID!): Order menu(id: ID, name: String): Menu menus(query: String, filter: MenuFilterInput, before: String, after: String, first: Int, last: Int): MenuCountableConnection menuItem(id: ID!): MenuItem @@ -3026,6 +3343,7 @@ enum ReportingPeriod { type RequestPasswordReset { errors: [Error!] + accountErrors: [AccountError!] } type Sale implements Node { @@ -3140,6 +3458,7 @@ type ServiceAccount implements Node { type ServiceAccountClearStoredPrivateMeta { errors: [Error!] + accountErrors: [AccountError!] serviceAccount: ServiceAccount } @@ -3157,11 +3476,13 @@ type ServiceAccountCountableEdge { type ServiceAccountCreate { errors: [Error!] authToken: String + accountErrors: [AccountError!] serviceAccount: ServiceAccount } type ServiceAccountDelete { errors: [Error!] + accountErrors: [AccountError!] serviceAccount: ServiceAccount } @@ -3178,11 +3499,13 @@ input ServiceAccountInput { type ServiceAccountUpdate { errors: [Error!] + accountErrors: [AccountError!] serviceAccount: ServiceAccount } type ServiceAccountUpdatePrivateMeta { errors: [Error!] + accountErrors: [AccountError!] serviceAccount: ServiceAccount } @@ -3190,6 +3513,23 @@ type SetPassword { token: String errors: [Error]! user: User + accountErrors: [AccountError!] +} + +type ShippingError { + field: String + message: String + code: ShippingErrorCode +} + +enum ShippingErrorCode { + ALREADY_EXISTS + GRAPHQL_ERROR + INVALID + MAX_LESS_THAN_MIN + NOT_FOUND + REQUIRED + UNIQUE } type ShippingMethod implements Node { @@ -3218,11 +3558,13 @@ enum ShippingMethodTypeEnum { type ShippingPriceBulkDelete { errors: [Error!] count: Int! + shippingErrors: [ShippingError!] } type ShippingPriceCreate { errors: [Error!] shippingZone: ShippingZone + shippingErrors: [ShippingError!] shippingMethod: ShippingMethod } @@ -3230,6 +3572,7 @@ type ShippingPriceDelete { errors: [Error!] shippingMethod: ShippingMethod shippingZone: ShippingZone + shippingErrors: [ShippingError!] } input ShippingPriceInput { @@ -3251,6 +3594,7 @@ type ShippingPriceTranslate { type ShippingPriceUpdate { errors: [Error!] shippingZone: ShippingZone + shippingErrors: [ShippingError!] shippingMethod: ShippingMethod } @@ -3266,6 +3610,7 @@ type ShippingZone implements Node { type ShippingZoneBulkDelete { errors: [Error!] count: Int! + shippingErrors: [ShippingError!] } type ShippingZoneCountableConnection { @@ -3282,10 +3627,12 @@ type ShippingZoneCountableEdge { type ShippingZoneCreate { errors: [Error!] shippingZone: ShippingZone + shippingErrors: [ShippingError!] } type ShippingZoneDelete { errors: [Error!] + shippingErrors: [ShippingError!] shippingZone: ShippingZone } @@ -3298,6 +3645,7 @@ input ShippingZoneInput { type ShippingZoneUpdate { errors: [Error!] shippingZone: ShippingZone + shippingErrors: [ShippingError!] } type Shop { @@ -3331,16 +3679,35 @@ type Shop { type ShopAddressUpdate { errors: [Error!] shop: Shop + shopErrors: [ShopError!] } type ShopDomainUpdate { errors: [Error!] shop: Shop + shopErrors: [ShopError!] +} + +type ShopError { + field: String + message: String + code: ShopErrorCode +} + +enum ShopErrorCode { + ALREADY_EXISTS + CANNOT_FETCH_TAX_RATES + GRAPHQL_ERROR + INVALID + NOT_FOUND + REQUIRED + UNIQUE } type ShopFetchTaxRates { errors: [Error!] shop: Shop + shopErrors: [ShopError!] } input ShopSettingsInput { @@ -3369,6 +3736,7 @@ input ShopSettingsTranslationInput { type ShopSettingsUpdate { errors: [Error!] shop: Shop + shopErrors: [ShopError!] } type ShopTranslation implements Node { @@ -3386,10 +3754,12 @@ input SiteDomainInput { type StaffBulkDelete { errors: [Error!] count: Int! + accountErrors: [AccountError!] } type StaffCreate { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -3406,6 +3776,7 @@ input StaffCreateInput { type StaffDelete { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -3425,6 +3796,7 @@ enum StaffMemberStatus { type StaffUpdate { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -3587,25 +3959,30 @@ input UserAddressInput { type UserAvatarDelete { errors: [Error!] user: User + accountErrors: [AccountError!] } type UserAvatarUpdate { errors: [Error!] user: User + accountErrors: [AccountError!] } type UserBulkSetActive { errors: [Error!] count: Int! + accountErrors: [AccountError!] } type UserClearStoredMeta { errors: [Error!] + accountErrors: [AccountError!] user: User } type UserClearStoredPrivateMeta { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -3634,11 +4011,13 @@ input UserCreateInput { type UserUpdateMeta { errors: [Error!] + accountErrors: [AccountError!] user: User } type UserUpdatePrivateMeta { errors: [Error!] + accountErrors: [AccountError!] user: User } @@ -3652,12 +4031,14 @@ type VariantImageAssign { errors: [Error!] productVariant: ProductVariant image: ProductImage + productErrors: [ProductError!] } type VariantImageUnassign { errors: [Error!] productVariant: ProductVariant image: ProductImage + productErrors: [ProductError!] } type VariantPricingInfo { diff --git a/src/misc.ts b/src/misc.ts index 74f410669..96bc1f921 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -480,5 +480,8 @@ export function findInEnum( } export function parseBoolean(a: string): boolean { + if (a === undefined) { + return true; + } return a === "true"; } diff --git a/src/products/components/ProductList/ProductList.tsx b/src/products/components/ProductList/ProductList.tsx index a69c7b877..feac3283c 100644 --- a/src/products/components/ProductList/ProductList.tsx +++ b/src/products/components/ProductList/ProductList.tsx @@ -101,12 +101,14 @@ interface ProductListProps ListActions, SortPage, WithStyles { + activeAttributeSortId: string; gridAttributes: AvailableInGridAttributes_grid_edges_node[]; products: ProductList_products_edges_node[]; } export const ProductList = withStyles(styles, { name: "ProductList" })( ({ + activeAttributeSortId, classes, settings, disabled, @@ -219,23 +221,35 @@ export const ProductList = withStyles(styles, { name: "ProductList" })( /> - {gridAttributesFromSettings.map(gridAttributeFromSettings => ( - - {maybe( - () => - gridAttributes.find( - gridAttribute => - getAttributeIdFromColumnValue( - gridAttributeFromSettings - ) === gridAttribute.id - ).name, - - )} - - ))} + {gridAttributesFromSettings.map(gridAttributeFromSettings => { + const attributeId = getAttributeIdFromColumnValue( + gridAttributeFromSettings + ); + + return ( + + onSort(ProductListUrlSortField.attribute, attributeId) + } + key={gridAttributeFromSettings} + > + {maybe( + () => + gridAttributes.find( + gridAttribute => attributeId === gridAttribute.id + ).name, + + )} + + ); + })} , FetchMoreProps, SortPage { + activeAttributeSortId: string; availableInGridAttributes: AvailableInGridAttributes_availableInGrid_edges_node[]; currencySymbol: string; gridAttributes: AvailableInGridAttributes_grid_edges_node[]; diff --git a/src/products/urls.ts b/src/products/urls.ts index 7a408857d..5ebfe8d31 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -31,18 +31,22 @@ export enum ProductListUrlFiltersEnum { } export type ProductListUrlFilters = Filters; export enum ProductListUrlSortField { + attribute = "attribute", name = "name", productType = "productType", status = "status", price = "price" } export type ProductListUrlSort = Sort; -export type ProductListUrlQueryParams = BulkAction & - Dialog & - ProductListUrlFilters & - ProductListUrlSort & - Pagination & - ActiveTab; +export interface ProductListUrlQueryParams + extends BulkAction, + Dialog, + ProductListUrlFilters, + ProductListUrlSort, + Pagination, + ActiveTab { + attributeId?: string; +} export const productListUrl = (params?: ProductListUrlQueryParams): string => productListPath + "?" + stringifyQs(params); diff --git a/src/products/views/ProductList/ProductList.tsx b/src/products/views/ProductList/ProductList.tsx index 366834bfc..7c9b01f8c 100644 --- a/src/products/views/ProductList/ProductList.tsx +++ b/src/products/views/ProductList/ProductList.tsx @@ -42,6 +42,7 @@ import { ProductListUrlDialog, ProductListUrlFilters, ProductListUrlQueryParams, + ProductListUrlSortField, productUrl } from "../../urls"; import { @@ -153,6 +154,15 @@ export const ProductList: React.StatelessComponent = ({ handleTabChange(tabs.length + 1); }; + const handleSort = (field: ProductListUrlSortField, attributeId?: string) => + navigate( + productListUrl({ + ...params, + ...getSortUrlVariables(field, params), + attributeId + }) + ); + const paginationState = createPaginationState(settings.rowNumber, params); const currencySymbol = maybe(() => shop.defaultCurrency, "USD"); const filter = getFilterVariables(params); @@ -230,18 +240,12 @@ export const ProductList: React.StatelessComponent = ({ return ( <> - navigate( - productListUrl({ - ...params, - ...getSortUrlVariables(field, params) - }) - ) - } + onSort={handleSort} availableInGridAttributes={maybe( () => attributes.data.availableInGrid.edges.map( diff --git a/src/products/views/ProductList/sort.ts b/src/products/views/ProductList/sort.ts index e5cbbe905..893190925 100644 --- a/src/products/views/ProductList/sort.ts +++ b/src/products/views/ProductList/sort.ts @@ -17,12 +17,20 @@ export function getSortQueryField( return ProductOrderField.TYPE; case ProductListUrlSortField.status: return ProductOrderField.PUBLISHED; + default: + return undefined; } } export function getSortQueryVariables( params: ProductListUrlQueryParams ): ProductOrder { + if (params.sort === ProductListUrlSortField.attribute) { + return { + attributeId: params.attributeId, + direction: getOrderDirection(params.asc) + }; + } return { direction: getOrderDirection(params.asc), field: getSortQueryField(params.sort) diff --git a/src/types.ts b/src/types.ts index 1ff50fea8..77ffb5cbd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -50,7 +50,7 @@ export interface ListProps { export interface SortPage { sort: Sort; - onSort: (field: TSortKey) => void; + onSort: (field: TSortKey, id?: string) => void; } export interface ListActionsWithoutToolbar { toggle: (id: string) => void; diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index e4d1e84ac..deb47b433 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -589,7 +589,8 @@ export interface ProductFilterInput { } export interface ProductOrder { - field: ProductOrderField; + field?: ProductOrderField | null; + attributeId?: string | null; direction: OrderDirection; } From 821675efb3c4704e2e6b59d608dd434e1a2a1622 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 26 Sep 2019 12:16:56 +0200 Subject: [PATCH 2/3] Fix types --- src/storybook/stories/products/ProductListPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storybook/stories/products/ProductListPage.tsx b/src/storybook/stories/products/ProductListPage.tsx index f9203dac4..e481c0e9f 100644 --- a/src/storybook/stories/products/ProductListPage.tsx +++ b/src/storybook/stories/products/ProductListPage.tsx @@ -34,6 +34,7 @@ const props: ProductListPageProps = { sort: ProductListUrlSortField.name } }, + activeAttributeSortId: undefined, availableInGridAttributes: attributes, defaultSettings: defaultListSettings[ListViews.PRODUCT_LIST], gridAttributes: attributes, From 7544174a3be8098a07076e061fd345842603002a Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Thu, 26 Sep 2019 12:17:02 +0200 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6de444ff..4b26e6c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,3 +24,4 @@ All notable, unreleased changes to this project will be documented in this file. - Add search bars - #172 by @dominik-zeglen - Add sorting to product list - #173 by @dominik-zeglen - Add Heroku integration - #175 by @bogdal +- Allow sorting products by attribute - #180 by @dominik-zeglen