File attributes (#884)

* Update changelog with file attributes

* Add file type attribute

* Update attribute properties form

* Update translation messages with file upload

* Create generic attributes component (#832)

* Create generic Attributes component

* Add story for Attributes component

* Remove deprecated attribute value type field from queries

* Update test snapshots of attributes component

* Add file upload field to atributes (#888)

* Add story for Attributes component

* Update test snapshots of attributes component

* Create file upload field in attributes

* Update upload file input data-test

* Update storybook test snapshots of attributes

* Add dedicated input props to file field

* Run Cypress using custom API

* Add missing error handling in file upload field

Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com>

* Add file attribute upload to page attributes (#894)

* Support upload file attribute for pages

* Update after review

* Add file attribute upload to variant attributes (#892)

* Support upload file attribute for variants

* Update after review

* Refactor attribute values errors merging

* Update after review

* Add file attribute upload to product attributes (#826)

* Support upload file attribute for products

* Update after review

* Refactor attribute values errors merging

* Refactor product attribute value delete handling

* Fix deleting file in file upload field

* Fix delete attribute values errors handling

* Add link to file upload field (#898)

* Update file attributes updates (#899)

* Update file attributes updates

* Refactor file uploads handling

* Move attributes utils to attributes directory

* Fix product channel listing updates

* Clear file field value if file is not passed as prop

* Delete attribute values before update (#908)

* Delete file attributes after file update

* Triggr CI

* Show skeleton in file upload field during loading

Co-authored-by: Krzysztof Wolski <krzysztof.k.wolski@gmail.com>
This commit is contained in:
Dawid Tarasiuk 2020-12-16 11:53:28 +01:00 committed by GitHub
parent c3d97b9114
commit 1e140853ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
115 changed files with 7335 additions and 1857 deletions

View file

@ -74,10 +74,21 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v1 uses: actions/checkout@v1
- name: Get custom API_URI
id: api_uri
# Search for API_URI in PR description
env:
pull_request_body: ${{ github.event.pull_request.body }}
prefix: API_URI=
pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/?
run: |
echo "::set-output name=custom_api_uri::$(echo $pull_request_body | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1)"
- name: Cypress run - name: Cypress run
uses: cypress-io/github-action@v2 uses: cypress-io/github-action@v2
env: env:
API_URI: ${{ secrets.API_URI }} API_URI: ${{ steps.api_uri.outputs.custom_api_uri || secrets.API_URI }}
APP_MOUNT_URI: ${{ secrets.APP_MOUNT_URI }} APP_MOUNT_URI: ${{ secrets.APP_MOUNT_URI }}
CYPRESS_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }} CYPRESS_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
CYPRESS_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }} CYPRESS_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}

View file

@ -10,6 +10,7 @@ All notable, unreleased changes to this project will be documented in this file.
- New Miscellaneous and Product refunds - #870 by @orzechdev - New Miscellaneous and Product refunds - #870 by @orzechdev
- Add zip code exclusion - #877 by @dominik-zeglen - Add zip code exclusion - #877 by @dominik-zeglen
- Update quantity column in Inventory part of Product Variant view - #904 by @dominik-zeglen - Update quantity column in Inventory part of Product Variant view - #904 by @dominik-zeglen
- Add file attributes - #884 by @orzechdev
# 2.11.1 # 2.11.1

View file

@ -741,6 +741,10 @@
"context": "product attribute type", "context": "product attribute type",
"string": "Dropdown" "string": "Dropdown"
}, },
"src_dot_attributes_dot_components_dot_AttributeDetails_dot_1376373679": {
"context": "file attribute type",
"string": "File"
},
"src_dot_attributes_dot_components_dot_AttributeDetails_dot_2592224946": { "src_dot_attributes_dot_components_dot_AttributeDetails_dot_2592224946": {
"context": "check to require attribute to have value", "context": "check to require attribute to have value",
"string": "Value Required" "string": "Value Required"
@ -1275,6 +1279,10 @@
"src_dot_channels_dot_views_dot_ChannelsList_dot_3499322424": { "src_dot_channels_dot_views_dot_ChannelsList_dot_3499322424": {
"string": "Channel deleted" "string": "Channel deleted"
}, },
"src_dot_chooseFile": {
"context": "button",
"string": "Choose file"
},
"src_dot_clear": { "src_dot_clear": {
"context": "button", "context": "button",
"string": "Clear" "string": "Clear"
@ -1532,6 +1540,22 @@
"src_dot_components_dot_AttributeUnassignDialog_dot_2037985699": { "src_dot_components_dot_AttributeUnassignDialog_dot_2037985699": {
"string": "Are you sure you want to unassign {attributeName} from {itemTypeName}?" "string": "Are you sure you want to unassign {attributeName} from {itemTypeName}?"
}, },
"src_dot_components_dot_Attributes_dot_attributesNumber": {
"context": "number of attributes",
"string": "{number} Attributes"
},
"src_dot_components_dot_Attributes_dot_header": {
"context": "attributes, section header",
"string": "Attributes"
},
"src_dot_components_dot_Attributes_dot_multipleValueLable": {
"context": "attribute values",
"string": "Values"
},
"src_dot_components_dot_Attributes_dot_valueLabel": {
"context": "attribute value",
"string": "Value"
},
"src_dot_components_dot_AutocompleteSelectMenu_dot_2332404293": { "src_dot_components_dot_AutocompleteSelectMenu_dot_2332404293": {
"string": "No results" "string": "No results"
}, },
@ -4060,22 +4084,6 @@
"context": "pages section name", "context": "pages section name",
"string": "Pages" "string": "Pages"
}, },
"src_dot_pages_dot_components_dot_PageAttributes_dot_1071548120": {
"context": "number of page attributes",
"string": "{number} Attributes"
},
"src_dot_pages_dot_components_dot_PageAttributes_dot_1148029984": {
"context": "attribute value",
"string": "Value"
},
"src_dot_pages_dot_components_dot_PageAttributes_dot_1207761269": {
"context": "attribute values",
"string": "Values"
},
"src_dot_pages_dot_components_dot_PageAttributes_dot_4153345096": {
"context": "page attributes, section header",
"string": "Attributes"
},
"src_dot_pages_dot_components_dot_PageDetailsPage_dot_1068617485": { "src_dot_pages_dot_components_dot_PageDetailsPage_dot_1068617485": {
"context": "page header", "context": "page header",
"string": "Create Page" "string": "Create Page"
@ -4580,22 +4588,6 @@
"context": "products section name", "context": "products section name",
"string": "Products" "string": "Products"
}, },
"src_dot_products_dot_components_dot_ProductAttributes_dot_1071548120": {
"context": "number of product attributes",
"string": "{number} Attributes"
},
"src_dot_products_dot_components_dot_ProductAttributes_dot_1148029984": {
"context": "attribute value",
"string": "Value"
},
"src_dot_products_dot_components_dot_ProductAttributes_dot_1207761269": {
"context": "attribute values",
"string": "Values"
},
"src_dot_products_dot_components_dot_ProductAttributes_dot_4153345096": {
"context": "product attributes, section header",
"string": "Attributes"
},
"src_dot_products_dot_components_dot_ProductCategoryAndCollectionsForm_dot_1755013298": { "src_dot_products_dot_components_dot_ProductCategoryAndCollectionsForm_dot_1755013298": {
"string": "Category" "string": "Category"
}, },
@ -4901,14 +4893,22 @@
"context": "product label", "context": "product label",
"string": "Published" "string": "Published"
}, },
"src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_2853608829": { "src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_attributesHeader": {
"context": "button", "context": "attributes, section header",
"string": "Save variant" "string": "Variant Attributes"
}, },
"src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_3726089650": { "src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_attributesSelectionHeader": {
"context": "attributes, section header",
"string": "Variant Selection Attributes"
},
"src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_deleteVariant": {
"context": "button", "context": "button",
"string": "Delete Variant" "string": "Delete Variant"
}, },
"src_dot_products_dot_components_dot_ProductVariantCreatePage_dot_saveVariant": {
"context": "button",
"string": "Save variant"
},
"src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_1134347598": { "src_dot_products_dot_components_dot_ProductVariantCreatorPage_dot_1134347598": {
"context": "variant price, header", "context": "variant price, header",
"string": "Price" "string": "Price"
@ -5049,6 +5049,14 @@
"context": "variant name", "context": "variant name",
"string": "New Variant" "string": "New Variant"
}, },
"src_dot_products_dot_components_dot_ProductVariantPage_dot_nonSelectionAttributes": {
"context": "attributes, section header",
"string": "Variant Attributes"
},
"src_dot_products_dot_components_dot_ProductVariantPage_dot_selectionAttributesHeader": {
"context": "attributes, section header",
"string": "Variant Selection Attributes"
},
"src_dot_products_dot_components_dot_ProductVariantPrice_dot_1099355007": { "src_dot_products_dot_components_dot_ProductVariantPrice_dot_1099355007": {
"context": "product pricing, section header", "context": "product pricing, section header",
"string": "Pricing" "string": "Pricing"

View file

@ -489,6 +489,7 @@ input AttributeInput {
enum AttributeInputTypeEnum { enum AttributeInputTypeEnum {
DROPDOWN DROPDOWN
MULTISELECT MULTISELECT
FILE
} }
type AttributeReorderValues { type AttributeReorderValues {
@ -565,6 +566,7 @@ type AttributeValue implements Node {
type: AttributeValueType @deprecated(reason: "Use the `inputType` field to determine the type of attribute's value. This field will be removed after 2020-07-31.") type: AttributeValueType @deprecated(reason: "Use the `inputType` field to determine the type of attribute's value. This field will be removed after 2020-07-31.")
translation(languageCode: LanguageCodeEnum!): AttributeValueTranslation translation(languageCode: LanguageCodeEnum!): AttributeValueTranslation
inputType: AttributeInputTypeEnum inputType: AttributeInputTypeEnum
file: File
} }
type AttributeValueBulkDelete { type AttributeValueBulkDelete {
@ -593,7 +595,9 @@ type AttributeValueDelete {
input AttributeValueInput { input AttributeValueInput {
id: ID id: ID
values: [String]! values: [String]
file: String
contentType: String
} }
type AttributeValueTranslatableContent implements Node { type AttributeValueTranslatableContent implements Node {
@ -658,6 +662,11 @@ enum AuthorizationKeyType {
GOOGLE_OAUTH2 GOOGLE_OAUTH2
} }
input BulkAttributeValueInput {
id: ID
values: [String]!
}
type BulkProductError { type BulkProductError {
field: String field: String
message: String message: String
@ -1959,6 +1968,11 @@ enum ExportScope {
FILTER FILTER
} }
type File {
url: String!
contentType: String
}
enum FileTypesEnum { enum FileTypesEnum {
CSV CSV
XLSX XLSX
@ -1966,7 +1980,7 @@ enum FileTypesEnum {
type FileUpload { type FileUpload {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
uploadedFile: UploadedFile uploadedFile: File
uploadErrors: [UploadError!]! uploadErrors: [UploadError!]!
} }
@ -4085,7 +4099,7 @@ type ProductType implements Node & ObjectWithMetadata {
products(channel: String, before: String, after: String, first: Int, last: Int): ProductCountableConnection @deprecated(reason: "Use the top-level `products` query with the `productTypes` filter.") products(channel: String, before: String, after: String, first: Int, last: Int): ProductCountableConnection @deprecated(reason: "Use the top-level `products` query with the `productTypes` filter.")
taxRate: TaxRateType taxRate: TaxRateType
taxType: TaxType taxType: TaxType
variantAttributes: [Attribute] variantAttributes(variantSelection: VariantAttributeScope): [Attribute]
productAttributes: [Attribute] productAttributes: [Attribute]
availableAttributes(filter: AttributeFilterInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection availableAttributes(filter: AttributeFilterInput, before: String, after: String, first: Int, last: Int): AttributeCountableConnection
} }
@ -4192,7 +4206,7 @@ type ProductVariant implements Node & ObjectWithMetadata {
channelListings: [ProductVariantChannelListing!] channelListings: [ProductVariantChannelListing!]
pricing: VariantPricingInfo pricing: VariantPricingInfo
isAvailable: Boolean @deprecated(reason: "Use the stock field instead. This field will be removed after 2020-07-31.") isAvailable: Boolean @deprecated(reason: "Use the stock field instead. This field will be removed after 2020-07-31.")
attributes: [SelectedAttribute!]! attributes(variantSelection: VariantAttributeScope): [SelectedAttribute!]!
costPrice: Money costPrice: Money
margin: Int margin: Int
quantityOrdered: Int quantityOrdered: Int
@ -4212,7 +4226,7 @@ type ProductVariantBulkCreate {
} }
input ProductVariantBulkCreateInput { input ProductVariantBulkCreateInput {
attributes: [AttributeValueInput]! attributes: [BulkAttributeValueInput]!
sku: String! sku: String!
trackInventory: Boolean trackInventory: Boolean
weight: WeightScalar weight: WeightScalar
@ -4645,6 +4659,8 @@ type ShippingMethod implements Node & ObjectWithMetadata {
name: String! name: String!
minimumOrderWeight: Weight minimumOrderWeight: Weight
maximumOrderWeight: Weight maximumOrderWeight: Weight
maximumDeliveryDays: Int
minimumDeliveryDays: Int
privateMetadata: [MetadataItem]! privateMetadata: [MetadataItem]!
metadata: [MetadataItem]! metadata: [MetadataItem]!
type: ShippingMethodTypeEnum type: ShippingMethodTypeEnum
@ -4741,6 +4757,8 @@ input ShippingPriceInput {
name: String name: String
minimumOrderWeight: WeightScalar minimumOrderWeight: WeightScalar
maximumOrderWeight: WeightScalar maximumOrderWeight: WeightScalar
maximumDeliveryDays: Int
minimumDeliveryDays: Int
type: ShippingMethodTypeEnum type: ShippingMethodTypeEnum
shippingZone: ID shippingZone: ID
} }
@ -5262,11 +5280,6 @@ enum UploadErrorCode {
GRAPHQL_ERROR GRAPHQL_ERROR
} }
type UploadedFile {
url: String!
contentType: String!
}
type User implements Node & ObjectWithMetadata { type User implements Node & ObjectWithMetadata {
id: ID! id: ID!
lastLogin: DateTime lastLogin: DateTime
@ -5359,6 +5372,12 @@ type VAT {
reducedRates: [ReducedRate]! reducedRates: [ReducedRate]!
} }
enum VariantAttributeScope {
ALL
VARIANT_SELECTION
NOT_VARIANT_SELECTION
}
type VariantImageAssign { type VariantImageAssign {
errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.") errors: [Error!]! @deprecated(reason: "Use typed errors with error codes. This field will be removed after 2020-07-31.")
productVariant: ProductVariant productVariant: ProductVariant

View file

@ -47,6 +47,13 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
description: "product attribute type" description: "product attribute type"
}), }),
value: AttributeInputTypeEnum.MULTISELECT value: AttributeInputTypeEnum.MULTISELECT
},
{
label: intl.formatMessage({
defaultMessage: "File",
description: "file attribute type"
}),
value: AttributeInputTypeEnum.FILE
} }
]; ];

View file

@ -172,15 +172,19 @@ const AttributePage: React.FC<AttributePageProps> = ({
errors={errors} errors={errors}
onChange={change} onChange={change}
/> />
<CardSpacer /> {data.inputType !== AttributeInputTypeEnum.FILE && (
<AttributeValues <>
disabled={disabled} <CardSpacer />
values={values} <AttributeValues
onValueAdd={onValueAdd} disabled={disabled}
onValueDelete={onValueDelete} values={values}
onValueReorder={onValueReorder} onValueAdd={onValueAdd}
onValueUpdate={onValueUpdate} onValueDelete={onValueDelete}
/> onValueReorder={onValueReorder}
onValueUpdate={onValueUpdate}
/>
</>
)}
<CardSpacer /> <CardSpacer />
<Metadata data={data} onChange={changeMetadata} /> <Metadata data={data} onChange={changeMetadata} />
</div> </div>

View file

@ -10,7 +10,10 @@ import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import { AttributeErrorFragment } from "@saleor/fragments/types/AttributeErrorFragment"; import { AttributeErrorFragment } from "@saleor/fragments/types/AttributeErrorFragment";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { AttributeTypeEnum } from "@saleor/types/globalTypes"; import {
AttributeInputTypeEnum,
AttributeTypeEnum
} from "@saleor/types/globalTypes";
import { getFormErrors } from "@saleor/utils/errors"; import { getFormErrors } from "@saleor/utils/errors";
import getAttributeErrorMessage from "@saleor/utils/errors/attribute"; import getAttributeErrorMessage from "@saleor/utils/errors/attribute";
import React from "react"; import React from "react";
@ -77,39 +80,43 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
/> />
</Typography> </Typography>
<Hr /> <Hr />
{data.type === AttributeTypeEnum.PRODUCT_TYPE && ( {data.inputType !== AttributeInputTypeEnum.FILE &&
<>
<ControlledCheckbox
name={"filterableInStorefront" as keyof FormData}
label={intl.formatMessage({
defaultMessage: "Use in Faceted Navigation",
description: "attribute is filterable in storefront"
})}
checked={data.filterableInStorefront}
onChange={onChange}
disabled={disabled}
/>
<FormSpacer />
</>
)}
{data.filterableInStorefront &&
data.type === AttributeTypeEnum.PRODUCT_TYPE && ( data.type === AttributeTypeEnum.PRODUCT_TYPE && (
<TextField <>
disabled={disabled} <ControlledCheckbox
error={!!formErrors.storefrontSearchPosition} name={"filterableInStorefront" as keyof FormData}
fullWidth label={intl.formatMessage({
helperText={getAttributeErrorMessage( defaultMessage: "Use in Faceted Navigation",
formErrors.storefrontSearchPosition, description: "attribute is filterable in storefront"
intl })}
checked={data.filterableInStorefront}
onChange={onChange}
disabled={disabled}
/>
{data.filterableInStorefront && (
<>
<FormSpacer />
<TextField
disabled={disabled}
error={!!formErrors.storefrontSearchPosition}
fullWidth
helperText={getAttributeErrorMessage(
formErrors.storefrontSearchPosition,
intl
)}
name={
"storefrontSearchPosition" as keyof AttributePageFormData
}
label={intl.formatMessage({
defaultMessage: "Position in faceted navigation",
description: "attribute position in storefront filters"
})}
value={data.storefrontSearchPosition}
onChange={onChange}
/>
</>
)} )}
name={"storefrontSearchPosition" as keyof AttributePageFormData} </>
label={intl.formatMessage({
defaultMessage: "Position in faceted navigation",
description: "attribute position in storefront filters"
})}
value={data.storefrontSearchPosition}
onChange={onChange}
/>
)} )}
<FormSpacer /> <FormSpacer />
<ControlledSwitch <ControlledSwitch
@ -129,50 +136,54 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
onChange={onChange} onChange={onChange}
disabled={disabled} disabled={disabled}
/> />
<CardSpacer /> {data.inputType !== AttributeInputTypeEnum.FILE && (
<Typography variant="subtitle1"> <>
<FormattedMessage <CardSpacer />
defaultMessage="Dashboard Properties" <Typography variant="subtitle1">
description="attribute properties regarding dashboard"
/>
</Typography>
<Hr />
<CardSpacer />
<ControlledCheckbox
name={"filterableInDashboard" as keyof FormData}
label={
<>
<FormattedMessage <FormattedMessage
defaultMessage="Use in Filtering" defaultMessage="Dashboard Properties"
description="use attribute in filtering" description="attribute properties regarding dashboard"
/> />
<Typography variant="caption"> </Typography>
<FormattedMessage defaultMessage="If enabled, youll be able to use this attribute to filter products in product list." /> <Hr />
</Typography> <CardSpacer />
</> <ControlledCheckbox
} name={"filterableInDashboard" as keyof FormData}
checked={data.filterableInDashboard} label={
onChange={onChange} <>
disabled={disabled} <FormattedMessage
/> defaultMessage="Use in Filtering"
<FormSpacer /> description="use attribute in filtering"
<ControlledCheckbox />
name={"availableInGrid" as keyof FormData} <Typography variant="caption">
label={ <FormattedMessage defaultMessage="If enabled, youll be able to use this attribute to filter products in product list." />
<> </Typography>
<FormattedMessage </>
defaultMessage="Add to Column Options" }
description="add attribute as column in product list table" checked={data.filterableInDashboard}
/> onChange={onChange}
<Typography variant="caption"> disabled={disabled}
<FormattedMessage defaultMessage="If enabled this attribute can be used as a column in product table." /> />
</Typography> <FormSpacer />
</> <ControlledCheckbox
} name={"availableInGrid" as keyof FormData}
checked={data.availableInGrid} label={
onChange={onChange} <>
disabled={disabled} <FormattedMessage
/> defaultMessage="Add to Column Options"
description="add attribute as column in product list table"
/>
<Typography variant="caption">
<FormattedMessage defaultMessage="If enabled this attribute can be used as a column in product table." />
</Typography>
</>
}
checked={data.availableInGrid}
onChange={onChange}
disabled={disabled}
/>
</>
)}
</CardContent> </CardContent>
</Card> </Card>
); );

View file

@ -2,8 +2,7 @@ import { AttributeDetailsFragment } from "@saleor/fragments/types/AttributeDetai
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
import { import {
AttributeInputTypeEnum, AttributeInputTypeEnum,
AttributeTypeEnum, AttributeTypeEnum
AttributeValueType
} from "@saleor/types/globalTypes"; } from "@saleor/types/globalTypes";
import { AttributeList_attributes_edges_node } from "./types/AttributeList"; import { AttributeList_attributes_edges_node } from "./types/AttributeList";
@ -31,17 +30,17 @@ export const attribute: AttributeDetailsFragment = {
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI0",
name: "John Doe", name: "John Doe",
slug: "john-doe", slug: "john-doe"
type: AttributeValueType.STRING
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI1",
name: "Milionare Pirate", name: "Milionare Pirate",
slug: "milionare-pirate", slug: "milionare-pirate"
type: AttributeValueType.STRING
} }
], ],
visibleInStorefront: true visibleInStorefront: true
@ -61,20 +60,20 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI0",
name: "John Doe", name: "John Doe",
slug: "john-doe", slug: "john-doe",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI1",
name: "Milionare Pirate", name: "Milionare Pirate",
slug: "milionare-pirate", slug: "milionare-pirate",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -93,38 +92,38 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE1",
name: "100g", name: "100g",
slug: "100g", slug: "100g",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE2", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE2",
name: "250g", name: "250g",
slug: "250g", slug: "250g",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE3", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE3",
name: "500g", name: "500g",
slug: "500g", slug: "500g",
sortOrder: 2, sortOrder: 2,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE4", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE4",
name: "1kg", name: "1kg",
slug: "1kg", slug: "1kg",
sortOrder: 3, sortOrder: 3,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -143,11 +142,11 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjY=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjY=",
name: "Saleor", name: "Saleor",
slug: "saleor", slug: "saleor",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -166,29 +165,29 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIx", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIx",
name: "100g", name: "100g",
slug: "100g", slug: "100g",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIy", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIy",
name: "250g", name: "250g",
slug: "250g", slug: "250g",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIz", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIz",
name: "500g", name: "500g",
slug: "500g", slug: "500g",
sortOrder: 2, sortOrder: 2,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -207,20 +206,20 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEz", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEz",
name: "Arabica", name: "Arabica",
slug: "arabica", slug: "arabica",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE0",
name: "Robusta", name: "Robusta",
slug: "robusta", slug: "robusta",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -239,29 +238,29 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM=",
name: "Round", name: "Round",
slug: "round", slug: "round",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjQ=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjQ=",
name: "V-Neck", name: "V-Neck",
slug: "v-neck", slug: "v-neck",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjU=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjU=",
name: "Polo", name: "Polo",
slug: "polo", slug: "polo",
sortOrder: 2, sortOrder: 2,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -280,20 +279,20 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE=",
name: "Blue", name: "Blue",
slug: "blue", slug: "blue",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI=",
name: "White", name: "White",
slug: "white", slug: "white",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -312,56 +311,56 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMw", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMw",
name: "Soft", name: "Soft",
slug: "soft", slug: "soft",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMx", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMx",
name: "Hard", name: "Hard",
slug: "hard", slug: "hard",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMy", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMy",
name: "Middle soft", name: "Middle soft",
slug: "middle-soft", slug: "middle-soft",
sortOrder: 2, sortOrder: 2,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMz", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMz",
name: "Middle hard", name: "Middle hard",
slug: "middle-hard", slug: "middle-hard",
sortOrder: 3, sortOrder: 3,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM0",
name: "Middle", name: "Middle",
slug: "middle", slug: "middle",
sortOrder: 4, sortOrder: 4,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM1",
name: "Very hard", name: "Very hard",
slug: "very-hard", slug: "very-hard",
sortOrder: 5, sortOrder: 5,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -380,20 +379,20 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE5", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE5",
name: "Sour", name: "Sour",
slug: "sour", slug: "sour",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIw", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIw",
name: "Sweet", name: "Sweet",
slug: "sweet", slug: "sweet",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -412,20 +411,20 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI4", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI4",
name: "English", name: "English",
slug: "english", slug: "english",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI5", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI5",
name: "Pirate", name: "Pirate",
slug: "pirate", slug: "pirate",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -444,20 +443,20 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI2", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI2",
name: "Mirumee Press", name: "Mirumee Press",
slug: "mirumee-press", slug: "mirumee-press",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI3", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI3",
name: "Saleor Publishing", name: "Saleor Publishing",
slug: "saleor-publishing", slug: "saleor-publishing",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],
@ -476,56 +475,56 @@ export const attributes: Array<AttributeList_attributes_edges_node &
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjc=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjc=",
name: "XS", name: "XS",
slug: "xs", slug: "xs",
sortOrder: 0, sortOrder: 0,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjg=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjg=",
name: "S", name: "S",
slug: "s", slug: "s",
sortOrder: 1, sortOrder: 1,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjk=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjk=",
name: "M", name: "M",
slug: "m", slug: "m",
sortOrder: 2, sortOrder: 2,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEw", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEw",
name: "L", name: "L",
slug: "l", slug: "l",
sortOrder: 3, sortOrder: 3,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEx", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEx",
name: "XL", name: "XL",
slug: "xl", slug: "xl",
sortOrder: 4, sortOrder: 4,
type: AttributeValueType.STRING,
value: "" value: ""
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEy", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEy",
name: "XXL", name: "XXL",
slug: "xxl", slug: "xxl",
sortOrder: 5, sortOrder: 5,
type: AttributeValueType.STRING,
value: "" value: ""
} }
], ],

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeCreateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType, AttributeErrorCode } from "./../../types/globalTypes"; import { AttributeCreateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: AttributeCreate // GraphQL mutation operation: AttributeCreate
@ -20,12 +20,18 @@ export interface AttributeCreate_attributeCreate_attribute_privateMetadata {
value: string; value: string;
} }
export interface AttributeCreate_attributeCreate_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeCreate_attributeCreate_attribute_values { export interface AttributeCreate_attributeCreate_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeCreate_attributeCreate_attribute_values_file | null;
} }
export interface AttributeCreate_attributeCreate_attribute { export interface AttributeCreate_attributeCreate_attribute {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes"; import { AttributeTypeEnum, AttributeInputTypeEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL query operation: AttributeDetails // GraphQL query operation: AttributeDetails
@ -20,12 +20,18 @@ export interface AttributeDetails_attribute_privateMetadata {
value: string; value: string;
} }
export interface AttributeDetails_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeDetails_attribute_values { export interface AttributeDetails_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeDetails_attribute_values_file | null;
} }
export interface AttributeDetails_attribute { export interface AttributeDetails_attribute {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeUpdateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType, AttributeErrorCode } from "./../../types/globalTypes"; import { AttributeUpdateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: AttributeUpdate // GraphQL mutation operation: AttributeUpdate
@ -20,12 +20,18 @@ export interface AttributeUpdate_attributeUpdate_attribute_privateMetadata {
value: string; value: string;
} }
export interface AttributeUpdate_attributeUpdate_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeUpdate_attributeUpdate_attribute_values { export interface AttributeUpdate_attributeUpdate_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeUpdate_attributeUpdate_attribute_values_file | null;
} }
export interface AttributeUpdate_attributeUpdate_attribute { export interface AttributeUpdate_attributeUpdate_attribute {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeValueCreateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType, AttributeErrorCode } from "./../../types/globalTypes"; import { AttributeValueCreateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: AttributeValueCreate // GraphQL mutation operation: AttributeValueCreate
@ -20,12 +20,18 @@ export interface AttributeValueCreate_attributeValueCreate_attribute_privateMeta
value: string; value: string;
} }
export interface AttributeValueCreate_attributeValueCreate_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeValueCreate_attributeValueCreate_attribute_values { export interface AttributeValueCreate_attributeValueCreate_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeValueCreate_attributeValueCreate_attribute_values_file | null;
} }
export interface AttributeValueCreate_attributeValueCreate_attribute { export interface AttributeValueCreate_attributeValueCreate_attribute {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType, AttributeErrorCode } from "./../../types/globalTypes"; import { AttributeTypeEnum, AttributeInputTypeEnum, AttributeErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: AttributeValueDelete // GraphQL mutation operation: AttributeValueDelete
@ -20,12 +20,18 @@ export interface AttributeValueDelete_attributeValueDelete_attribute_privateMeta
value: string; value: string;
} }
export interface AttributeValueDelete_attributeValueDelete_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeValueDelete_attributeValueDelete_attribute_values { export interface AttributeValueDelete_attributeValueDelete_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeValueDelete_attributeValueDelete_attribute_values_file | null;
} }
export interface AttributeValueDelete_attributeValueDelete_attribute { export interface AttributeValueDelete_attributeValueDelete_attribute {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeValueCreateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType, AttributeErrorCode } from "./../../types/globalTypes"; import { AttributeValueCreateInput, AttributeTypeEnum, AttributeInputTypeEnum, AttributeErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: AttributeValueUpdate // GraphQL mutation operation: AttributeValueUpdate
@ -20,12 +20,18 @@ export interface AttributeValueUpdate_attributeValueUpdate_attribute_privateMeta
value: string; value: string;
} }
export interface AttributeValueUpdate_attributeValueUpdate_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeValueUpdate_attributeValueUpdate_attribute_values { export interface AttributeValueUpdate_attributeValueUpdate_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeValueUpdate_attributeValueUpdate_attribute_values_file | null;
} }
export interface AttributeValueUpdate_attributeValueUpdate_attribute { export interface AttributeValueUpdate_attributeValueUpdate_attribute {

View file

@ -0,0 +1,106 @@
import { FileUpload } from "@saleor/files/types/FileUpload";
import { AttributeErrorFragment } from "@saleor/fragments/types/AttributeErrorFragment";
import { SelectedVariantAttributeFragment } from "@saleor/fragments/types/SelectedVariantAttributeFragment";
import { UploadErrorFragment } from "@saleor/fragments/types/UploadErrorFragment";
import { FormsetData } from "@saleor/hooks/useFormset";
import { PageDetails_page_attributes } from "@saleor/pages/types/PageDetails";
import {
AttributeInputTypeEnum,
AttributeValueInput
} from "@saleor/types/globalTypes";
import { MutationFetchResult } from "react-apollo";
import { AttributeValueDelete } from "../types/AttributeValueDelete";
export const isFileValueUnused = (
attributesWithNewFileValue: FormsetData<null, File>,
existingAttribute:
| PageDetails_page_attributes
| SelectedVariantAttributeFragment
) => {
if (existingAttribute.attribute.inputType !== AttributeInputTypeEnum.FILE) {
return false;
}
if (existingAttribute.values.length === 0) {
return false;
}
const modifiedAttribute = attributesWithNewFileValue.find(
dataAttribute => dataAttribute.id === existingAttribute.attribute.id
);
return !!modifiedAttribute;
};
export const mergeFileUploadErrors = (
uploadFilesResult: Array<MutationFetchResult<FileUpload>>
): UploadErrorFragment[] =>
uploadFilesResult.reduce((errors, uploadFileResult) => {
const uploadErrors = uploadFileResult?.data?.fileUpload?.uploadErrors;
if (uploadErrors) {
return [...errors, ...uploadErrors];
}
return errors;
}, []);
export const mergeAttributeValueDeleteErrors = (
deleteAttributeValuesResult: Array<MutationFetchResult<AttributeValueDelete>>
): AttributeErrorFragment[] =>
deleteAttributeValuesResult.reduce((errors, deleteValueResult) => {
const deleteErrors = deleteValueResult?.data?.attributeValueDelete?.errors;
if (deleteErrors) {
return [...errors, ...deleteErrors];
}
return errors;
}, []);
export const getFileValuesToUploadFromAttributes = (
attributesWithNewFileValue: FormsetData<null, File>
) => attributesWithNewFileValue.filter(fileAttribute => !!fileAttribute.value);
export const getFileValuesRemovedFromAttributes = (
attributesWithNewFileValue: FormsetData<null, File>
) => attributesWithNewFileValue.filter(attribute => !attribute.value);
export const getAttributesOfRemovedFiles = (
fileAttributesRemoved: FormsetData<null, File>
) =>
fileAttributesRemoved.map(attribute => ({
file: undefined,
id: attribute.id,
values: []
}));
export const getAttributesOfUploadedFiles = (
fileValuesToUpload: FormsetData<null, File>,
uploadFilesResult: Array<MutationFetchResult<FileUpload>>
) =>
uploadFilesResult.map((uploadFileResult, index) => {
const attribute = fileValuesToUpload[index];
return {
file: uploadFileResult.data.fileUpload.uploadedFile.url,
id: attribute.id,
values: []
};
});
export const getAttributesAfterFileAttributesUpdate = (
attributesWithNewFileValue: FormsetData<null, File>,
uploadFilesResult: Array<MutationFetchResult<FileUpload>>
): AttributeValueInput[] => {
const removedFileValues = getFileValuesRemovedFromAttributes(
attributesWithNewFileValue
);
const fileValuesToUpload = getFileValuesToUploadFromAttributes(
attributesWithNewFileValue
);
const removedFileAttributes = getAttributesOfRemovedFiles(removedFileValues);
const uploadedFileAttributes = getAttributesOfUploadedFiles(
fileValuesToUpload,
uploadFilesResult
);
return uploadedFileAttributes.concat(removedFileAttributes);
};

View file

@ -0,0 +1,88 @@
import { AttributeInput } from "@saleor/components/Attributes";
import {
FileUpload,
FileUploadVariables
} from "@saleor/files/types/FileUpload";
import { FormsetData } from "@saleor/hooks/useFormset";
import { PageDetails_page_attributes } from "@saleor/pages/types/PageDetails";
import {
AttributeInputTypeEnum,
AttributeValueInput
} from "@saleor/types/globalTypes";
import { MutationFetchResult } from "react-apollo";
import {
AttributeValueDelete,
AttributeValueDeleteVariables
} from "../types/AttributeValueDelete";
import { getFileValuesToUploadFromAttributes, isFileValueUnused } from "./data";
interface AttributesArgs {
attributes: AttributeInput[];
updatedFileAttributes: AttributeValueInput[];
}
export const prepareAttributesInput = ({
attributes,
updatedFileAttributes
}: AttributesArgs): AttributeValueInput[] =>
attributes.map(attribute => {
if (attribute.data.inputType === AttributeInputTypeEnum.FILE) {
const updatedFileAttribute = updatedFileAttributes.find(
attributeWithNewFile => attribute.id === attributeWithNewFile.id
);
if (updatedFileAttribute) {
return {
file: updatedFileAttribute.file,
id: updatedFileAttribute.id
};
}
return {
file:
attribute.data.selectedValues &&
attribute.data.selectedValues[0]?.file?.url,
id: attribute.id
};
}
return {
id: attribute.id,
values: attribute.value[0] === "" ? [] : attribute.value
};
});
export const handleUploadMultipleFiles = async (
attributesWithNewFileValue: FormsetData<null, File>,
uploadFile: (
variables: FileUploadVariables
) => Promise<MutationFetchResult<FileUpload>>
) =>
Promise.all(
getFileValuesToUploadFromAttributes(attributesWithNewFileValue).map(
fileAttribute =>
uploadFile({
file: fileAttribute.value
})
)
);
export const handleDeleteMultipleAttributeValues = async (
attributesWithNewFileValue: FormsetData<null, File>,
attributes: PageDetails_page_attributes[],
deleteAttributeValue: (
variables: AttributeValueDeleteVariables
) => Promise<MutationFetchResult<AttributeValueDelete>>
) =>
Promise.all(
attributes.map(existingAttribute => {
const fileValueUnused = isFileValueUnused(
attributesWithNewFileValue,
existingAttribute
);
if (fileValueUnused) {
return deleteAttributeValue({
id: existingAttribute.values[0].id
});
}
})
);

View file

@ -3,7 +3,10 @@ import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import { getStringOrPlaceholder } from "@saleor/misc"; import { getStringOrPlaceholder } from "@saleor/misc";
import { ReorderEvent } from "@saleor/types"; import { ReorderEvent } from "@saleor/types";
import { AttributeErrorCode } from "@saleor/types/globalTypes"; import {
AttributeErrorCode,
AttributeInputTypeEnum
} from "@saleor/types/globalTypes";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler"; import createMetadataCreateHandler from "@saleor/utils/handlers/metadataCreateHandler";
import { import {
@ -54,6 +57,33 @@ function areValuesEqual(
return a.name === b.name; return a.name === b.name;
} }
function getSimpleAttributeData(
data: AttributePageFormData,
values: AttributeValueEditDialogFormData[]
) {
return {
...data,
metadata: undefined,
privateMetadata: undefined,
storefrontSearchPosition: parseInt(data.storefrontSearchPosition, 10),
values: values.map(value => ({
name: value.name
}))
};
}
function getFileAttributeData(
data: AttributePageFormData,
values: AttributeValueEditDialogFormData[]
) {
return {
...getSimpleAttributeData(data, values),
availableInGrid: undefined,
filterableInDashboard: undefined,
filterableInStorefront: undefined
};
}
const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => { const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
@ -115,15 +145,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
setValues(move(values[oldIndex], values, areValuesEqual, newIndex)); setValues(move(values[oldIndex], values, areValuesEqual, newIndex));
const handleCreate = async (data: AttributePageFormData) => { const handleCreate = async (data: AttributePageFormData) => {
const input = { const input =
...data, data.inputType === AttributeInputTypeEnum.FILE
metadata: undefined, ? getFileAttributeData(data, values)
privateMetadata: undefined, : getSimpleAttributeData(data, values);
storefrontSearchPosition: parseInt(data.storefrontSearchPosition, 0),
values: values.map(value => ({
name: value.name
}))
};
const result = await attributeCreate({ const result = await attributeCreate({
variables: { variables: {
@ -163,10 +188,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
saveButtonBarState={attributeCreateOpts.status} saveButtonBarState={attributeCreateOpts.status}
values={values.map((value, valueIndex) => ({ values={values.map((value, valueIndex) => ({
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: valueIndex.toString(), id: valueIndex.toString(),
slug: slugify(value.name).toLowerCase(), slug: slugify(value.name).toLowerCase(),
sortOrder: valueIndex, sortOrder: valueIndex,
type: null,
value: null, value: null,
...value ...value
}))} }))}

View file

@ -0,0 +1,24 @@
import Attributes, { AttributesProps } from "@saleor/components/Attributes";
import { storiesOf } from "@storybook/react";
import React from "react";
import Decorator from "../../storybook/Decorator";
import { ATTRIBUTES, ATTRIBUTES_SELECTED } from "./fixtures";
const props: AttributesProps = {
attributes: ATTRIBUTES,
disabled: false,
errors: [],
loading: false,
onChange: () => undefined,
onFileChange: () => undefined,
onMultiChange: () => undefined
};
storiesOf("Attributes / Attributes", module)
.addDecorator(Decorator)
.add("default", () => <Attributes {...props} />)
.add("selected", () => (
<Attributes {...props} attributes={ATTRIBUTES_SELECTED} />
))
.add("disabled", () => <Attributes {...props} disabled={true} />);

View file

@ -13,30 +13,45 @@ import MultiAutocompleteSelectField, {
import SingleAutocompleteSelectField, { import SingleAutocompleteSelectField, {
SingleAutocompleteChoiceType SingleAutocompleteChoiceType
} from "@saleor/components/SingleAutocompleteSelectField"; } from "@saleor/components/SingleAutocompleteSelectField";
import { AttributeValueFragment } from "@saleor/fragments/types/AttributeValueFragment";
import { PageErrorWithAttributesFragment } from "@saleor/fragments/types/PageErrorWithAttributesFragment";
import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment";
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { ProductDetails_product_attributes_attribute_values } from "@saleor/products/types/ProductDetails";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { getProductErrorMessage } from "@saleor/utils/errors"; import { getProductErrorMessage } from "@saleor/utils/errors";
import getPageErrorMessage from "@saleor/utils/errors/page";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import {
defineMessages,
FormattedMessage,
IntlShape,
useIntl
} from "react-intl";
export interface ProductAttributeInputData { import FileUploadField, { FileChoiceType } from "../FileUploadField";
import { VariantAttributeScope } from "./types";
export interface AttributeInputData {
inputType: AttributeInputTypeEnum; inputType: AttributeInputTypeEnum;
variantAttributeScope?: VariantAttributeScope;
isRequired: boolean; isRequired: boolean;
values: ProductDetails_product_attributes_attribute_values[]; values: AttributeValueFragment[];
selectedValues?: AttributeValueFragment[];
} }
export type ProductAttributeInput = FormsetAtomicData< export type AttributeInput = FormsetAtomicData<AttributeInputData, string[]>;
ProductAttributeInputData, export type AttributeFileInput = FormsetAtomicData<AttributeInputData, File[]>;
string[] export interface AttributesProps {
>; attributes: AttributeInput[];
export interface ProductAttributesProps {
attributes: ProductAttributeInput[];
disabled: boolean; disabled: boolean;
errors: ProductErrorWithAttributesFragment[]; loading: boolean;
errors: Array<
ProductErrorWithAttributesFragment | PageErrorWithAttributesFragment
>;
title?: React.ReactNode;
onChange: FormsetChange; onChange: FormsetChange;
onMultiChange: FormsetChange; onMultiChange: FormsetChange;
onFileChange?: FormsetChange; // TODO: temporairy optional, should be changed to required, after all pages implement it
} }
const useStyles = makeStyles( const useStyles = makeStyles(
@ -78,15 +93,26 @@ const useStyles = makeStyles(
display: "flex", display: "flex",
flex: 1 flex: 1
}, },
fileField: {
float: "right"
},
rotate: { rotate: {
transform: "rotate(180deg)" transform: "rotate(180deg)"
},
uploadFileButton: {
float: "right"
},
uploadFileContent: {
color: theme.palette.primary.main,
float: "right",
fontSize: "1rem"
} }
}), }),
{ name: "ProductAttributes" } { name: "Attributes" }
); );
function getMultiChoices( function getMultiChoices(
values: ProductDetails_product_attributes_attribute_values[] values: AttributeValueFragment[]
): MultiAutocompleteChoiceType[] { ): MultiAutocompleteChoiceType[] {
return values.map(value => ({ return values.map(value => ({
label: value.name, label: value.name,
@ -95,7 +121,7 @@ function getMultiChoices(
} }
function getMultiDisplayValue( function getMultiDisplayValue(
attribute: ProductAttributeInput attribute: AttributeInput
): MultiAutocompleteChoiceType[] { ): MultiAutocompleteChoiceType[] {
return attribute.value.map(attributeValue => { return attribute.value.map(attributeValue => {
const definedAttributeValue = attribute.data.values.find( const definedAttributeValue = attribute.data.values.find(
@ -116,7 +142,7 @@ function getMultiDisplayValue(
} }
function getSingleChoices( function getSingleChoices(
values: ProductDetails_product_attributes_attribute_values[] values: AttributeValueFragment[]
): SingleAutocompleteChoiceType[] { ): SingleAutocompleteChoiceType[] {
return values.map(value => ({ return values.map(value => ({
label: value.name, label: value.name,
@ -124,12 +150,67 @@ function getSingleChoices(
})); }));
} }
const ProductAttributes: React.FC<ProductAttributesProps> = ({ function getFileChoice(attribute: AttributeInput): FileChoiceType {
const attributeValue = attribute.value[0];
const definedAttributeValue = attribute.data.values.find(
definedValue => definedValue.slug === attributeValue
);
if (definedAttributeValue) {
return {
file: definedAttributeValue.file,
label: definedAttributeValue.name,
value: definedAttributeValue.slug
};
}
return {
label: attributeValue,
value: attributeValue
};
}
const messages = defineMessages({
attributesNumber: {
defaultMessage: "{number} Attributes",
description: "number of attributes"
},
header: {
defaultMessage: "Attributes",
description: "attributes, section header"
},
multipleValueLable: {
defaultMessage: "Values",
description: "attribute values"
},
valueLabel: {
defaultMessage: "Value",
description: "attribute value"
}
});
function getErrorMessage(
err: ProductErrorWithAttributesFragment | PageErrorWithAttributesFragment,
intl: IntlShape
): string {
switch (err?.__typename) {
case "ProductError":
return getProductErrorMessage(err, intl);
case "PageError":
return getPageErrorMessage(err, intl);
}
}
const Attributes: React.FC<AttributesProps> = ({
attributes, attributes,
disabled, disabled,
loading,
errors, errors,
title,
onChange, onChange,
onMultiChange onMultiChange,
onFileChange
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const classes = useStyles({}); const classes = useStyles({});
@ -138,19 +219,13 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
return ( return (
<Card className={classes.card}> <Card className={classes.card}>
<CardTitle <CardTitle title={title || intl.formatMessage(messages.header)} />
title={intl.formatMessage({
defaultMessage: "Attributes",
description: "product attributes, section header"
})}
/>
<CardContent className={classes.cardContent}> <CardContent className={classes.cardContent}>
<div className={classes.expansionBar}> <div className={classes.expansionBar}>
<div className={classes.expansionBarLabelContainer}> <div className={classes.expansionBarLabelContainer}>
<Typography className={classes.expansionBarLabel} variant="caption"> <Typography className={classes.expansionBarLabel} variant="caption">
<FormattedMessage <FormattedMessage
defaultMessage="{number} Attributes" {...messages.attributesNumber}
description="number of product attributes"
values={{ values={{
number: attributes.length number: attributes.length
}} }}
@ -160,7 +235,7 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
<IconButton <IconButton
className={classes.expansionBarButton} className={classes.expansionBarButton}
onClick={toggleExpansion} onClick={toggleExpansion}
data-test="product-attributes-expand" data-test="attributes-expand"
> >
<ArrowDropDownIcon <ArrowDropDownIcon
className={classNames(classes.expansionBarButtonIcon, { className={classNames(classes.expansionBarButtonIcon, {
@ -183,13 +258,32 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
<Grid className={classes.attributeSection} variant="uniform"> <Grid className={classes.attributeSection} variant="uniform">
<div <div
className={classes.attributeSectionLabel} className={classes.attributeSectionLabel}
data-test="product-attribute-label" data-test="attribute-label"
> >
<Typography>{attribute.label}</Typography> <Typography>{attribute.label}</Typography>
</div> </div>
<div data-test="product-attribute-value"> <div data-test="attribute-value">
{attribute.data.inputType === {attribute.data.inputType ===
AttributeInputTypeEnum.DROPDOWN ? ( AttributeInputTypeEnum.FILE ? (
<FileUploadField
className={classes.fileField}
disabled={disabled}
loading={loading}
file={getFileChoice(attribute)}
onFileUpload={file =>
onFileChange(attribute.id, file)
}
onFileDelete={() =>
onFileChange(attribute.id, undefined)
}
error={!!error}
helperText={getErrorMessage(error, intl)}
inputProps={{
name: `attribute:${attribute.label}`
}}
/>
) : attribute.data.inputType ===
AttributeInputTypeEnum.DROPDOWN ? (
<SingleAutocompleteSelectField <SingleAutocompleteSelectField
choices={getSingleChoices(attribute.data.values)} choices={getSingleChoices(attribute.data.values)}
disabled={disabled} disabled={disabled}
@ -202,12 +296,9 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
} }
emptyOption={!attribute.data.isRequired} emptyOption={!attribute.data.isRequired}
error={!!error} error={!!error}
helperText={getProductErrorMessage(error, intl)} helperText={getErrorMessage(error, intl)}
name={`attribute:${attribute.label}`} name={`attribute:${attribute.label}`}
label={intl.formatMessage({ label={intl.formatMessage(messages.valueLabel)}
defaultMessage: "Value",
description: "attribute value"
})}
value={attribute.value[0]} value={attribute.value[0]}
onChange={event => onChange={event =>
onChange(attribute.id, event.target.value) onChange(attribute.id, event.target.value)
@ -218,12 +309,12 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
<MultiAutocompleteSelectField <MultiAutocompleteSelectField
choices={getMultiChoices(attribute.data.values)} choices={getMultiChoices(attribute.data.values)}
displayValues={getMultiDisplayValue(attribute)} displayValues={getMultiDisplayValue(attribute)}
disabled={disabled}
error={!!error} error={!!error}
helperText={getProductErrorMessage(error, intl)} helperText={getErrorMessage(error, intl)}
label={intl.formatMessage({ label={intl.formatMessage(
defaultMessage: "Values", messages.multipleValueLable
description: "attribute values" )}
})}
name={`attribute:${attribute.label}`} name={`attribute:${attribute.label}`}
value={attribute.value} value={attribute.value}
onChange={event => onChange={event =>
@ -243,5 +334,5 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
</Card> </Card>
); );
}; };
ProductAttributes.displayName = "ProductAttributes"; Attributes.displayName = "Attributes";
export default ProductAttributes; export default Attributes;

View file

@ -0,0 +1,109 @@
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { AttributeInput } from "./Attributes";
const DROPDOWN_ATTRIBUTE: AttributeInput = {
data: {
inputType: AttributeInputTypeEnum.DROPDOWN,
isRequired: true,
values: [
{
__typename: "AttributeValue",
file: null,
id: "fdinugiffgffd",
name: "Dropdown First Value",
slug: "dropdown-first-value"
},
{
__typename: "AttributeValue",
file: null,
id: "fdhfdhdihidff",
name: "Dropdown Second Value",
slug: "dropdown-second-value"
}
]
},
id: "ifudbgidfsb",
label: "Dropdown Attribute",
value: []
};
const MULTISELECT_ATTRIBUTE: AttributeInput = {
data: {
inputType: AttributeInputTypeEnum.MULTISELECT,
isRequired: true,
values: [
{
__typename: "AttributeValue",
file: null,
id: "terteretregtt",
name: "Multiselect First Value",
slug: "multiselect-first-value"
},
{
__typename: "AttributeValue",
file: null,
id: "tyueyryetopwr",
name: "Multiselect Second Value",
slug: "multiselect-second-value"
},
{
__typename: "AttributeValue",
file: null,
id: "truiwrtweirqd",
name: "Multiselect Third Value",
slug: "multiselect-third-value"
}
]
},
id: "idffuidhffl",
label: "Multiselect Attribute",
value: []
};
const FILE_ATTRIBUTE: AttributeInput = {
data: {
inputType: AttributeInputTypeEnum.FILE,
isRequired: true,
values: [
{
__typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "gdghdgdhkkdae",
name: "File First Value",
slug: "file-first-value"
}
]
},
id: "ifudbgidfsb",
label: "File Attribute",
value: []
};
export const ATTRIBUTES: AttributeInput[] = [
DROPDOWN_ATTRIBUTE,
MULTISELECT_ATTRIBUTE,
FILE_ATTRIBUTE
];
export const ATTRIBUTES_SELECTED: AttributeInput[] = [
{
...DROPDOWN_ATTRIBUTE,
value: [DROPDOWN_ATTRIBUTE.data.values[0].slug]
},
{
...MULTISELECT_ATTRIBUTE,
value: [
MULTISELECT_ATTRIBUTE.data.values[0].slug,
MULTISELECT_ATTRIBUTE.data.values[1].slug
]
},
{
...FILE_ATTRIBUTE,
value: [FILE_ATTRIBUTE.data.values[0].slug]
}
];

View file

@ -0,0 +1,3 @@
export { default } from "./Attributes";
export * from "./Attributes";
export * from "./types";

View file

@ -0,0 +1,5 @@
export enum VariantAttributeScope {
ALL = "ALL",
VARIANT_SELECTION = "VARIANT_SELECTION",
NOT_VARIANT_SELECTION = "NOT_VARIANT_SELECTION"
}

View file

@ -0,0 +1,68 @@
import CardDecorator from "@saleor/storybook/CardDecorator";
import Decorator from "@saleor/storybook/Decorator";
import { storiesOf } from "@storybook/react";
import React, { useState } from "react";
import FileUploadField, { FileUploadFieldProps } from "./FileUploadField";
import * as fixtures from "./fixtures";
const props: FileUploadFieldProps = {
disabled: false,
file: { label: undefined, value: undefined },
inputProps: {
name: "country",
placeholder: "Select country"
},
loading: false,
onFileDelete: () => undefined,
onFileUpload: () => undefined
};
const InteractiveStory: React.FC = () => {
const [file, setFile] = useState<File>();
return (
<FileUploadField
disabled={false}
loading={false}
file={{
label: file?.name,
value: file?.name
}}
onFileUpload={file => setFile(file)}
onFileDelete={() => setFile(null)}
/>
);
};
storiesOf("Generics / File upload field", module)
.addDecorator(CardDecorator)
.addDecorator(Decorator)
.add("default", () => <FileUploadField {...props} />)
.add("with ready to upload file", () => (
<FileUploadField
{...props}
file={{
label: "some_file.png",
value: "some_file.png"
}}
/>
))
.add("with uploaded file", () => (
<FileUploadField
{...props}
file={{
file: fixtures.UPLOADED_FILE,
label: "some_file_with_link.png",
value: "some_file_with_link.png"
}}
/>
))
.add("with error", () => (
<FileUploadField
{...props}
error={true}
helperText="Something went wrong"
/>
))
.add("interactive", () => <InteractiveStory />);

View file

@ -0,0 +1,147 @@
import { makeStyles } from "@material-ui/core";
import Button from "@material-ui/core/Button";
import IconButton from "@material-ui/core/IconButton";
import Typography from "@material-ui/core/Typography";
import DeleteIcon from "@material-ui/icons/Delete";
import { FileFragment } from "@saleor/fragments/types/FileFragment";
import { commonMessages } from "@saleor/intl";
import React from "react";
import { useIntl } from "react-intl";
import Skeleton from "../Skeleton";
export interface FileChoiceType {
label: string;
value: string;
file?: FileFragment;
}
export interface FileUploadFieldProps {
inputProps?: React.DetailedHTMLProps<
React.InputHTMLAttributes<HTMLInputElement>,
HTMLInputElement
>;
className?: string;
disabled: boolean;
loading: boolean;
file: FileChoiceType;
error?: boolean;
helperText?: string;
onFileUpload: (file: File) => void;
onFileDelete: () => void;
}
const useStyles = makeStyles(
theme => ({
errorText: {
color: theme.palette.error.light
},
fileField: {
display: "none"
},
fileUrl: {
color: theme.palette.primary.main,
textDecoration: "none"
},
uploadFileContent: {
alignItems: "center",
color: theme.palette.primary.main,
display: "flex",
fontSize: "1rem"
},
uploadFileName: {
minWidth: "6rem"
}
}),
{ name: "FileUploadField" }
);
const FileUploadField: React.FC<FileUploadFieldProps> = props => {
const {
loading,
disabled,
file,
className,
error,
helperText,
onFileUpload,
onFileDelete,
inputProps
} = props;
const classes = useStyles({});
const intl = useIntl();
const fileInputAnchor = React.createRef<HTMLInputElement>();
const clickFileInput = () => fileInputAnchor.current.click();
const handleFileDelete = () => {
fileInputAnchor.current.value = "";
onFileDelete();
};
React.useEffect(() => {
if (!file.value) {
fileInputAnchor.current.value = "";
}
}, [file]);
return (
<>
<div className={className}>
{file.label ? (
<div className={classes.uploadFileContent}>
<div className={classes.uploadFileName}>
{loading ? (
<Skeleton />
) : (
<a
href={file.file?.url}
target="blank"
className={classes.fileUrl}
>
{file.label}
</a>
)}
</div>
<IconButton
color="primary"
onClick={handleFileDelete}
disabled={disabled || loading}
data-test="button-delete-file"
>
<DeleteIcon />
</IconButton>
</div>
) : (
<div>
<Button
onClick={clickFileInput}
disabled={disabled || loading}
variant="outlined"
color="primary"
data-test="button-upload-file"
>
{intl.formatMessage(commonMessages.chooseFile)}
</Button>
</div>
)}
{error && (
<Typography variant="caption" className={classes.errorText}>
{helperText}
</Typography>
)}
</div>
<input
className={classes.fileField}
id="fileUpload"
onChange={event => onFileUpload(event.target.files[0])}
type="file"
data-test="upload-file-input"
ref={fileInputAnchor}
{...inputProps}
/>
</>
);
};
FileUploadField.displayName = "FileUploadField";
export default FileUploadField;

View file

@ -0,0 +1,7 @@
import { FileFragment } from "@saleor/fragments/types/FileFragment";
export const UPLOADED_FILE: FileFragment = {
__typename: "File",
contentType: "image/png",
url: "some_url_to_image.png"
};

View file

@ -0,0 +1,2 @@
export { default } from "./FileUploadField";
export * from "./FileUploadField";

View file

@ -83,6 +83,7 @@ export interface MultiAutocompleteSelectFieldProps
placeholder?: string; placeholder?: string;
helperText?: string; helperText?: string;
label?: string; label?: string;
disabled?: boolean;
fetchChoices?: (value: string) => void; fetchChoices?: (value: string) => void;
onChange: (event: React.ChangeEvent<any>) => void; onChange: (event: React.ChangeEvent<any>) => void;
} }
@ -105,6 +106,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
name, name,
placeholder, placeholder,
value, value,
disabled,
fetchChoices, fetchChoices,
onChange, onChange,
onFetchMore, onFetchMore,
@ -167,6 +169,7 @@ const MultiAutocompleteSelectFieldComponent: React.FC<MultiAutocompleteSelectFie
helperText={helperText} helperText={helperText}
label={label} label={label}
fullWidth={true} fullWidth={true}
disabled={disabled}
/> />
{isOpen && (!!inputValue || !!choices.length) && ( {isOpen && (!!inputValue || !!choices.length) && (
<MultiAutocompleteSelectFieldContent <MultiAutocompleteSelectFieldContent

25
src/files/mutations.ts Normal file
View file

@ -0,0 +1,25 @@
import { uploadErrorFragment } from "@saleor/fragments/errors";
import { fileFragment } from "@saleor/fragments/file";
import makeMutation from "@saleor/hooks/makeMutation";
import gql from "graphql-tag";
import { FileUpload, FileUploadVariables } from "./types/FileUpload";
const fileUploadMutation = gql`
${fileFragment}
${uploadErrorFragment}
mutation FileUpload($file: Upload!) {
fileUpload(file: $file) {
uploadedFile {
...FileFragment
}
uploadErrors {
...UploadErrorFragment
}
}
}
`;
export const useFileUploadMutation = makeMutation<
FileUpload,
FileUploadVariables
>(fileUploadMutation);

View file

@ -0,0 +1,35 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { UploadErrorCode } from "./../../types/globalTypes";
// ====================================================
// GraphQL mutation operation: FileUpload
// ====================================================
export interface FileUpload_fileUpload_uploadedFile {
__typename: "File";
url: string;
contentType: string | null;
}
export interface FileUpload_fileUpload_uploadErrors {
__typename: "UploadError";
code: UploadErrorCode;
field: string | null;
}
export interface FileUpload_fileUpload {
__typename: "FileUpload";
uploadedFile: FileUpload_fileUpload_uploadedFile | null;
uploadErrors: FileUpload_fileUpload_uploadErrors[];
}
export interface FileUpload {
fileUpload: FileUpload_fileUpload | null;
}
export interface FileUploadVariables {
file: any;
}

View file

@ -1,7 +1,20 @@
import gql from "graphql-tag"; import gql from "graphql-tag";
import { fileFragment } from "./file";
import { metadataFragment } from "./metadata"; import { metadataFragment } from "./metadata";
export const attributeValueFragment = gql`
${fileFragment}
fragment AttributeValueFragment on AttributeValue {
id
name
slug
file {
...FileFragment
}
}
`;
export const attributeFragment = gql` export const attributeFragment = gql`
fragment AttributeFragment on Attribute { fragment AttributeFragment on Attribute {
id id
@ -17,6 +30,7 @@ export const attributeFragment = gql`
export const attributeDetailsFragment = gql` export const attributeDetailsFragment = gql`
${attributeFragment} ${attributeFragment}
${metadataFragment} ${metadataFragment}
${attributeValueFragment}
fragment AttributeDetailsFragment on Attribute { fragment AttributeDetailsFragment on Attribute {
...AttributeFragment ...AttributeFragment
...MetadataFragment ...MetadataFragment
@ -25,10 +39,7 @@ export const attributeDetailsFragment = gql`
storefrontSearchPosition storefrontSearchPosition
valueRequired valueRequired
values { values {
id ...AttributeValueFragment
name
slug
type
} }
} }
`; `;

View file

@ -206,3 +206,10 @@ export const collectionsErrorFragment = gql`
field field
} }
`; `;
export const uploadErrorFragment = gql`
fragment UploadErrorFragment on UploadError {
code
field
}
`;

8
src/fragments/file.ts Normal file
View file

@ -0,0 +1,8 @@
import gql from "graphql-tag";
export const fileFragment = gql`
fragment FileFragment on File {
url
contentType
}
`;

View file

@ -1,5 +1,6 @@
import gql from "graphql-tag"; import gql from "graphql-tag";
import { attributeValueFragment } from "./attributes";
import { metadataFragment } from "./metadata"; import { metadataFragment } from "./metadata";
export const pageFragment = gql` export const pageFragment = gql`
@ -12,6 +13,7 @@ export const pageFragment = gql`
`; `;
export const pageAttributesFragment = gql` export const pageAttributesFragment = gql`
${attributeValueFragment}
fragment PageAttributesFragment on Page { fragment PageAttributesFragment on Page {
attributes { attributes {
attribute { attribute {
@ -21,15 +23,11 @@ export const pageAttributesFragment = gql`
inputType inputType
valueRequired valueRequired
values { values {
id ...AttributeValueFragment
name
slug
} }
} }
values { values {
id ...AttributeValueFragment
name
slug
} }
} }
pageType { pageType {
@ -41,9 +39,7 @@ export const pageAttributesFragment = gql`
inputType inputType
valueRequired valueRequired
values { values {
id ...AttributeValueFragment
name
slug
} }
} }
} }

View file

@ -1,5 +1,6 @@
import gql from "graphql-tag"; import gql from "graphql-tag";
import { attributeValueFragment } from "./attributes";
import { metadataFragment } from "./metadata"; import { metadataFragment } from "./metadata";
import { taxTypeFragment } from "./taxes"; import { taxTypeFragment } from "./taxes";
import { weightFragment } from "./weight"; import { weightFragment } from "./weight";
@ -113,6 +114,7 @@ export const productFragment = gql`
export const productVariantAttributesFragment = gql` export const productVariantAttributesFragment = gql`
${priceRangeFragment} ${priceRangeFragment}
${attributeValueFragment}
fragment ProductVariantAttributesFragment on Product { fragment ProductVariantAttributesFragment on Product {
id id
attributes { attributes {
@ -123,26 +125,20 @@ export const productVariantAttributesFragment = gql`
inputType inputType
valueRequired valueRequired
values { values {
id ...AttributeValueFragment
name
slug
} }
} }
values { values {
id ...AttributeValueFragment
name
slug
} }
} }
productType { productType {
id id
variantAttributes { variantAttributes(variantSelection: VARIANT_SELECTION) {
id id
name name
values { values {
id ...AttributeValueFragment
name
slug
} }
} }
} }
@ -228,7 +224,35 @@ export const productFragmentDetails = gql`
} }
`; `;
export const variantAttributeFragment = gql`
${attributeValueFragment}
fragment VariantAttributeFragment on Attribute {
id
name
slug
inputType
valueRequired
values {
...AttributeValueFragment
}
}
`;
export const selectedVariantAttributeFragment = gql`
${attributeValueFragment}
${variantAttributeFragment}
fragment SelectedVariantAttributeFragment on SelectedAttribute {
attribute {
...VariantAttributeFragment
}
values {
...AttributeValueFragment
}
}
`;
export const fragmentVariant = gql` export const fragmentVariant = gql`
${selectedVariantAttributeFragment}
${priceRangeFragment} ${priceRangeFragment}
${fragmentProductImage} ${fragmentProductImage}
${stockFragment} ${stockFragment}
@ -238,23 +262,13 @@ export const fragmentVariant = gql`
fragment ProductVariant on ProductVariant { fragment ProductVariant on ProductVariant {
id id
...MetadataFragment ...MetadataFragment
attributes { selectionAttributes: attributes(variantSelection: VARIANT_SELECTION) {
attribute { ...SelectedVariantAttributeFragment
id }
name nonSelectionAttributes: attributes(
slug variantSelection: NOT_VARIANT_SELECTION
valueRequired ) {
values { ...SelectedVariantAttributeFragment
id
name
slug
}
}
values {
id
name
slug
}
} }
images { images {
id id

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeTypeEnum, AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes"; import { AttributeTypeEnum, AttributeInputTypeEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL fragment: AttributeDetailsFragment // GraphQL fragment: AttributeDetailsFragment
@ -20,12 +20,18 @@ export interface AttributeDetailsFragment_privateMetadata {
value: string; value: string;
} }
export interface AttributeDetailsFragment_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeDetailsFragment_values { export interface AttributeDetailsFragment_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
type: AttributeValueType | null; file: AttributeDetailsFragment_values_file | null;
} }
export interface AttributeDetailsFragment { export interface AttributeDetailsFragment {

View file

@ -0,0 +1,21 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL fragment: AttributeValueFragment
// ====================================================
export interface AttributeValueFragment_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface AttributeValueFragment {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: AttributeValueFragment_file | null;
}

View file

@ -0,0 +1,13 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
// ====================================================
// GraphQL fragment: FileFragment
// ====================================================
export interface FileFragment {
__typename: "File";
url: string;
contentType: string | null;
}

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// GraphQL fragment: PageAttributesFragment // GraphQL fragment: PageAttributesFragment
// ==================================================== // ====================================================
export interface PageAttributesFragment_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageAttributesFragment_attributes_attribute_values { export interface PageAttributesFragment_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageAttributesFragment_attributes_attribute_values_file | null;
} }
export interface PageAttributesFragment_attributes_attribute { export interface PageAttributesFragment_attributes_attribute {
@ -25,11 +32,18 @@ export interface PageAttributesFragment_attributes_attribute {
values: (PageAttributesFragment_attributes_attribute_values | null)[] | null; values: (PageAttributesFragment_attributes_attribute_values | null)[] | null;
} }
export interface PageAttributesFragment_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageAttributesFragment_attributes_values { export interface PageAttributesFragment_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageAttributesFragment_attributes_values_file | null;
} }
export interface PageAttributesFragment_attributes { export interface PageAttributesFragment_attributes {
@ -38,11 +52,18 @@ export interface PageAttributesFragment_attributes {
values: (PageAttributesFragment_attributes_values | null)[]; values: (PageAttributesFragment_attributes_values | null)[];
} }
export interface PageAttributesFragment_pageType_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageAttributesFragment_pageType_attributes_values { export interface PageAttributesFragment_pageType_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageAttributesFragment_pageType_attributes_values_file | null;
} }
export interface PageAttributesFragment_pageType_attributes { export interface PageAttributesFragment_pageType_attributes {

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// GraphQL fragment: PageDetailsFragment // GraphQL fragment: PageDetailsFragment
// ==================================================== // ====================================================
export interface PageDetailsFragment_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageDetailsFragment_attributes_attribute_values { export interface PageDetailsFragment_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageDetailsFragment_attributes_attribute_values_file | null;
} }
export interface PageDetailsFragment_attributes_attribute { export interface PageDetailsFragment_attributes_attribute {
@ -25,11 +32,18 @@ export interface PageDetailsFragment_attributes_attribute {
values: (PageDetailsFragment_attributes_attribute_values | null)[] | null; values: (PageDetailsFragment_attributes_attribute_values | null)[] | null;
} }
export interface PageDetailsFragment_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageDetailsFragment_attributes_values { export interface PageDetailsFragment_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageDetailsFragment_attributes_values_file | null;
} }
export interface PageDetailsFragment_attributes { export interface PageDetailsFragment_attributes {
@ -38,11 +52,18 @@ export interface PageDetailsFragment_attributes {
values: (PageDetailsFragment_attributes_values | null)[]; values: (PageDetailsFragment_attributes_values | null)[];
} }
export interface PageDetailsFragment_pageType_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageDetailsFragment_pageType_attributes_values { export interface PageDetailsFragment_pageType_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageDetailsFragment_pageType_attributes_values_file | null;
} }
export interface PageDetailsFragment_pageType_attributes { export interface PageDetailsFragment_pageType_attributes {

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTyp
// GraphQL fragment: Product // GraphQL fragment: Product
// ==================================================== // ====================================================
export interface Product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface Product_attributes_attribute_values { export interface Product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: Product_attributes_attribute_values_file | null;
} }
export interface Product_attributes_attribute { export interface Product_attributes_attribute {
@ -25,11 +32,18 @@ export interface Product_attributes_attribute {
values: (Product_attributes_attribute_values | null)[] | null; values: (Product_attributes_attribute_values | null)[] | null;
} }
export interface Product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface Product_attributes_values { export interface Product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: Product_attributes_values_file | null;
} }
export interface Product_attributes { export interface Product_attributes {
@ -38,11 +52,18 @@ export interface Product_attributes {
values: (Product_attributes_values | null)[]; values: (Product_attributes_values | null)[];
} }
export interface Product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface Product_productType_variantAttributes_values { export interface Product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: Product_productType_variantAttributes_values_file | null;
} }
export interface Product_productType_variantAttributes { export interface Product_productType_variantAttributes {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { WeightUnitsEnum } from "./../../types/globalTypes"; import { AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL fragment: ProductVariant // GraphQL fragment: ProductVariant
@ -20,33 +20,92 @@ export interface ProductVariant_privateMetadata {
value: string; value: string;
} }
export interface ProductVariant_attributes_attribute_values { export interface ProductVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariant_selectionAttributes_attribute_values_file | null;
} }
export interface ProductVariant_attributes_attribute { export interface ProductVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (ProductVariant_attributes_attribute_values | null)[] | null; values: (ProductVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface ProductVariant_attributes_values { export interface ProductVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariant_selectionAttributes_values_file | null;
} }
export interface ProductVariant_attributes { export interface ProductVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: ProductVariant_attributes_attribute; attribute: ProductVariant_selectionAttributes_attribute;
values: (ProductVariant_attributes_values | null)[]; values: (ProductVariant_selectionAttributes_values | null)[];
}
export interface ProductVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface ProductVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (ProductVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface ProductVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariant_nonSelectionAttributes_values_file | null;
}
export interface ProductVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: ProductVariant_nonSelectionAttributes_attribute;
values: (ProductVariant_nonSelectionAttributes_values | null)[];
} }
export interface ProductVariant_images { export interface ProductVariant_images {
@ -195,7 +254,8 @@ export interface ProductVariant {
id: string; id: string;
metadata: (ProductVariant_metadata | null)[]; metadata: (ProductVariant_metadata | null)[];
privateMetadata: (ProductVariant_privateMetadata | null)[]; privateMetadata: (ProductVariant_privateMetadata | null)[];
attributes: ProductVariant_attributes[]; selectionAttributes: ProductVariant_selectionAttributes[];
nonSelectionAttributes: ProductVariant_nonSelectionAttributes[];
images: (ProductVariant_images | null)[] | null; images: (ProductVariant_images | null)[] | null;
name: string; name: string;
product: ProductVariant_product; product: ProductVariant_product;

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// GraphQL fragment: ProductVariantAttributesFragment // GraphQL fragment: ProductVariantAttributesFragment
// ==================================================== // ====================================================
export interface ProductVariantAttributesFragment_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantAttributesFragment_attributes_attribute_values { export interface ProductVariantAttributesFragment_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantAttributesFragment_attributes_attribute_values_file | null;
} }
export interface ProductVariantAttributesFragment_attributes_attribute { export interface ProductVariantAttributesFragment_attributes_attribute {
@ -25,11 +32,18 @@ export interface ProductVariantAttributesFragment_attributes_attribute {
values: (ProductVariantAttributesFragment_attributes_attribute_values | null)[] | null; values: (ProductVariantAttributesFragment_attributes_attribute_values | null)[] | null;
} }
export interface ProductVariantAttributesFragment_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantAttributesFragment_attributes_values { export interface ProductVariantAttributesFragment_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantAttributesFragment_attributes_values_file | null;
} }
export interface ProductVariantAttributesFragment_attributes { export interface ProductVariantAttributesFragment_attributes {
@ -38,11 +52,18 @@ export interface ProductVariantAttributesFragment_attributes {
values: (ProductVariantAttributesFragment_attributes_values | null)[]; values: (ProductVariantAttributesFragment_attributes_values | null)[];
} }
export interface ProductVariantAttributesFragment_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantAttributesFragment_productType_variantAttributes_values { export interface ProductVariantAttributesFragment_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantAttributesFragment_productType_variantAttributes_values_file | null;
} }
export interface ProductVariantAttributesFragment_productType_variantAttributes { export interface ProductVariantAttributesFragment_productType_variantAttributes {

View file

@ -0,0 +1,33 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: SelectedProductTypeVariantAttributeFragment
// ====================================================
export interface SelectedProductTypeVariantAttributeFragment_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SelectedProductTypeVariantAttributeFragment_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SelectedProductTypeVariantAttributeFragment_values_file | null;
}
export interface SelectedProductTypeVariantAttributeFragment {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SelectedProductTypeVariantAttributeFragment_values | null)[] | null;
}

View file

@ -0,0 +1,53 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: SelectedProductVariantAttributeFragment
// ====================================================
export interface SelectedProductVariantAttributeFragment_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SelectedProductVariantAttributeFragment_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SelectedProductVariantAttributeFragment_attribute_values_file | null;
}
export interface SelectedProductVariantAttributeFragment_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SelectedProductVariantAttributeFragment_attribute_values | null)[] | null;
}
export interface SelectedProductVariantAttributeFragment_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SelectedProductVariantAttributeFragment_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SelectedProductVariantAttributeFragment_values_file | null;
}
export interface SelectedProductVariantAttributeFragment {
__typename: "SelectedAttribute";
attribute: SelectedProductVariantAttributeFragment_attribute;
values: (SelectedProductVariantAttributeFragment_values | null)[];
}

View file

@ -0,0 +1,53 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: SelectedVariantAttributeFragment
// ====================================================
export interface SelectedVariantAttributeFragment_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SelectedVariantAttributeFragment_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SelectedVariantAttributeFragment_attribute_values_file | null;
}
export interface SelectedVariantAttributeFragment_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SelectedVariantAttributeFragment_attribute_values | null)[] | null;
}
export interface SelectedVariantAttributeFragment_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SelectedVariantAttributeFragment_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SelectedVariantAttributeFragment_values_file | null;
}
export interface SelectedVariantAttributeFragment {
__typename: "SelectedAttribute";
attribute: SelectedVariantAttributeFragment_attribute;
values: (SelectedVariantAttributeFragment_values | null)[];
}

View file

@ -0,0 +1,15 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { UploadErrorCode } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: UploadErrorFragment
// ====================================================
export interface UploadErrorFragment {
__typename: "UploadError";
code: UploadErrorCode;
field: string | null;
}

View file

@ -0,0 +1,33 @@
/* tslint:disable */
/* eslint-disable */
// This file was automatically generated and should not be edited.
import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// ====================================================
// GraphQL fragment: VariantAttributeFragment
// ====================================================
export interface VariantAttributeFragment_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantAttributeFragment_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantAttributeFragment_values_file | null;
}
export interface VariantAttributeFragment {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (VariantAttributeFragment_values | null)[] | null;
}

View file

@ -7,6 +7,10 @@ export const commonMessages = defineMessages({
catalog: { catalog: {
defaultMessage: "Catalog" defaultMessage: "Catalog"
}, },
chooseFile: {
defaultMessage: "Choose file",
description: "button"
},
customApps: { customApps: {
defaultMessage: "Local Apps" defaultMessage: "Local Apps"
}, },

View file

@ -1,247 +0,0 @@
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import IconButton from "@material-ui/core/IconButton";
import makeStyles from "@material-ui/core/styles/makeStyles";
import Typography from "@material-ui/core/Typography";
import ArrowDropDownIcon from "@material-ui/icons/ArrowDropDown";
import CardTitle from "@saleor/components/CardTitle";
import Grid from "@saleor/components/Grid";
import Hr from "@saleor/components/Hr";
import MultiAutocompleteSelectField, {
MultiAutocompleteChoiceType
} from "@saleor/components/MultiAutocompleteSelectField";
import SingleAutocompleteSelectField, {
SingleAutocompleteChoiceType
} from "@saleor/components/SingleAutocompleteSelectField";
import { PageDetailsFragment_pageType_attributes_values } from "@saleor/fragments/types/PageDetailsFragment";
import { PageErrorWithAttributesFragment } from "@saleor/fragments/types/PageErrorWithAttributesFragment";
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import getPageErrorMessage from "@saleor/utils/errors/page";
import classNames from "classnames";
import React from "react";
import { FormattedMessage, useIntl } from "react-intl";
export interface PageAttributeInputData {
inputType: AttributeInputTypeEnum;
isRequired: boolean;
values: PageDetailsFragment_pageType_attributes_values[];
}
export type PageAttributeInput = FormsetAtomicData<
PageAttributeInputData,
string[]
>;
export interface PageAttributesProps {
attributes: PageAttributeInput[];
disabled: boolean;
errors: PageErrorWithAttributesFragment[];
onChange: FormsetChange;
onMultiChange: FormsetChange;
}
const useStyles = makeStyles(
theme => ({
attributeSection: {
"&:last-of-type": {
paddingBottom: 0
},
padding: theme.spacing(2, 0)
},
attributeSectionLabel: {
alignItems: "center",
display: "flex"
},
card: {
overflow: "visible"
},
cardContent: {
"&:last-child": {
paddingBottom: theme.spacing(1)
},
paddingTop: theme.spacing(1)
},
expansionBar: {
display: "flex"
},
expansionBarButton: {
marginBottom: theme.spacing(1)
},
expansionBarButtonIcon: {
transition: theme.transitions.duration.short + "ms"
},
expansionBarLabel: {
color: theme.palette.text.disabled,
fontSize: 14
},
expansionBarLabelContainer: {
alignItems: "center",
display: "flex",
flex: 1
},
rotate: {
transform: "rotate(180deg)"
}
}),
{ name: "PageAttributes" }
);
function getMultiChoices(
values: PageDetailsFragment_pageType_attributes_values[]
): MultiAutocompleteChoiceType[] {
return values.map(value => ({
label: value.name,
value: value.slug
}));
}
function getMultiDisplayValue(
attribute: PageAttributeInput
): MultiAutocompleteChoiceType[] {
return attribute.value.map(attributeValue => {
const definedAttributeValue = attribute.data.values.find(
definedValue => definedValue.slug === attributeValue
);
if (!!definedAttributeValue) {
return {
label: definedAttributeValue.name,
value: definedAttributeValue.slug
};
}
return {
label: attributeValue,
value: attributeValue
};
});
}
function getSingleChoices(
values: PageDetailsFragment_pageType_attributes_values[]
): SingleAutocompleteChoiceType[] {
return values.map(value => ({
label: value.name,
value: value.slug
}));
}
const PageAttributes: React.FC<PageAttributesProps> = ({
attributes,
disabled,
errors,
onChange,
onMultiChange
}) => {
const intl = useIntl();
const classes = useStyles({});
const [expanded, setExpansionStatus] = React.useState(true);
const toggleExpansion = () => setExpansionStatus(!expanded);
return (
<Card className={classes.card}>
<CardTitle
title={intl.formatMessage({
defaultMessage: "Attributes",
description: "page attributes, section header"
})}
/>
<CardContent className={classes.cardContent}>
<div className={classes.expansionBar}>
<div className={classes.expansionBarLabelContainer}>
<Typography className={classes.expansionBarLabel} variant="caption">
<FormattedMessage
defaultMessage="{number} Attributes"
description="number of page attributes"
values={{
number: attributes.length
}}
/>
</Typography>
</div>
<IconButton
className={classes.expansionBarButton}
onClick={toggleExpansion}
data-test="page-attributes-expand"
>
<ArrowDropDownIcon
className={classNames(classes.expansionBarButtonIcon, {
[classes.rotate]: expanded
})}
/>
</IconButton>
</div>
{expanded && attributes.length > 0 && (
<>
<Hr />
{attributes.map((attribute, attributeIndex) => {
const error = errors.find(err =>
err.attributes?.includes(attribute.id)
);
return (
<React.Fragment key={attribute.id}>
{attributeIndex > 0 && <Hr />}
<Grid className={classes.attributeSection} variant="uniform">
<div
className={classes.attributeSectionLabel}
data-test="page-attribute-label"
>
<Typography>{attribute.label}</Typography>
</div>
<div data-test="page-attribute-value">
{attribute.data.inputType ===
AttributeInputTypeEnum.DROPDOWN ? (
<SingleAutocompleteSelectField
choices={getSingleChoices(attribute.data.values)}
disabled={disabled}
displayValue={
attribute.data.values.find(
value => value.slug === attribute.value[0]
)?.name ||
attribute.value[0] ||
""
}
emptyOption={!attribute.data.isRequired}
error={!!error}
helperText={getPageErrorMessage(error, intl)}
name={`attribute:${attribute.label}`}
label={intl.formatMessage({
defaultMessage: "Value",
description: "attribute value"
})}
value={attribute.value[0]}
onChange={event =>
onChange(attribute.id, event.target.value)
}
allowCustomValues={!attribute.data.isRequired}
/>
) : (
<MultiAutocompleteSelectField
choices={getMultiChoices(attribute.data.values)}
displayValues={getMultiDisplayValue(attribute)}
error={!!error}
helperText={getPageErrorMessage(error, intl)}
label={intl.formatMessage({
defaultMessage: "Values",
description: "attribute values"
})}
name={`attribute:${attribute.label}`}
value={attribute.value}
onChange={event =>
onMultiChange(attribute.id, event.target.value)
}
allowCustomValues={!attribute.data.isRequired}
/>
)}
</div>
</Grid>
</React.Fragment>
);
})}
</>
)}
</CardContent>
</Card>
);
};
PageAttributes.displayName = "PageAttributes";
export default PageAttributes;

View file

@ -1,2 +0,0 @@
export { default } from "./PageAttributes";
export * from "./PageAttributes";

View file

@ -1,4 +1,5 @@
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import Attributes from "@saleor/components/Attributes";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
@ -18,13 +19,12 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { PageDetails_page } from "../../types/PageDetails"; import { PageDetails_page } from "../../types/PageDetails";
import PageAttributes from "../PageAttributes";
import PageInfo from "../PageInfo"; import PageInfo from "../PageInfo";
import PageOrganizeContent from "../PageOrganizeContent"; import PageOrganizeContent from "../PageOrganizeContent";
import PageForm, { PageData } from "./form"; import PageForm, { PageData } from "./form";
export interface PageDetailsPageProps { export interface PageDetailsPageProps {
disabled: boolean; loading: boolean;
errors: PageErrorWithAttributesFragment[]; errors: PageErrorWithAttributesFragment[];
page: PageDetails_page; page: PageDetails_page;
pageTypes?: SearchPageTypes_search_edges_node[]; pageTypes?: SearchPageTypes_search_edges_node[];
@ -38,7 +38,7 @@ export interface PageDetailsPageProps {
} }
const PageDetailsPage: React.FC<PageDetailsPageProps> = ({ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
disabled, loading,
errors, errors,
page, page,
pageTypes, pageTypes,
@ -75,7 +75,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
<div> <div>
<PageInfo <PageInfo
data={data} data={data}
disabled={disabled} disabled={loading}
errors={errors} errors={errors}
onChange={change} onChange={change}
onContentChange={handlers.changeContent} onContentChange={handlers.changeContent}
@ -85,7 +85,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
errors={errors} errors={errors}
allowEmptySlug={!pageExists} allowEmptySlug={!pageExists}
description={data.seoDescription} description={data.seoDescription}
disabled={disabled} disabled={loading}
descriptionPlaceholder={""} // TODO: Cast description to string and trim it descriptionPlaceholder={""} // TODO: Cast description to string and trim it
onChange={change} onChange={change}
slug={data.slug} slug={data.slug}
@ -99,12 +99,14 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
/> />
<CardSpacer /> <CardSpacer />
{data.attributes.length > 0 && ( {data.attributes.length > 0 && (
<PageAttributes <Attributes
attributes={data.attributes} attributes={data.attributes}
disabled={disabled} disabled={loading}
loading={loading}
errors={errors} errors={errors}
onChange={handlers.changeAttribute} onChange={handlers.selectAttribute}
onMultiChange={handlers.changeAttributeMulti} onMultiChange={handlers.selectAttributeMulti}
onFileChange={handlers.selectAttributeFile}
/> />
)} )}
<CardSpacer /> <CardSpacer />
@ -115,7 +117,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
<VisibilityCard <VisibilityCard
data={data} data={data}
errors={errors} errors={errors}
disabled={disabled} disabled={loading}
messages={{ messages={{
hiddenLabel: intl.formatMessage({ hiddenLabel: intl.formatMessage({
defaultMessage: "Hidden", defaultMessage: "Hidden",
@ -141,7 +143,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
<PageOrganizeContent <PageOrganizeContent
data={data} data={data}
errors={errors} errors={errors}
disabled={disabled} disabled={loading}
pageTypes={pageTypes} pageTypes={pageTypes}
pageType={pageType} pageType={pageType}
pageTypeInputDisplayValue={pageType?.name || ""} pageTypeInputDisplayValue={pageType?.name || ""}
@ -153,7 +155,7 @@ const PageDetailsPage: React.FC<PageDetailsPageProps> = ({
</div> </div>
</Grid> </Grid>
<SaveButtonBar <SaveButtonBar
disabled={disabled || !hasChanged} disabled={loading || !hasChanged}
state={saveButtonBarState} state={saveButtonBarState}
onCancel={onBack} onCancel={onBack}
onDelete={page === null ? undefined : onRemove} onDelete={page === null ? undefined : onRemove}

View file

@ -1,18 +1,26 @@
import { OutputData } from "@editorjs/editorjs"; import { OutputData } from "@editorjs/editorjs";
import { AttributeInput } from "@saleor/components/Attributes";
import { MetadataFormData } from "@saleor/components/Metadata"; import { MetadataFormData } from "@saleor/components/Metadata";
import { RichTextEditorChange } from "@saleor/components/RichTextEditor"; import { RichTextEditorChange } from "@saleor/components/RichTextEditor";
import { PageTypeFragment } from "@saleor/fragments/types/PageTypeFragment"; import { PageTypeFragment } from "@saleor/fragments/types/PageTypeFragment";
import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm"; import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
import useFormset, { FormsetChange } from "@saleor/hooks/useFormset"; import useFormset, {
FormsetChange,
FormsetData
} from "@saleor/hooks/useFormset";
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { import {
PageDetails_page, PageDetails_page,
PageDetails_page_pageType PageDetails_page_pageType
} from "@saleor/pages/types/PageDetails"; } from "@saleor/pages/types/PageDetails";
import { getAttributeInputFromPage } from "@saleor/pages/utils/data"; import {
getAttributeInputFromPage,
getAttributesDisplayData
} from "@saleor/pages/utils/data";
import { createPageTypeSelectHandler } from "@saleor/pages/utils/handlers"; import { createPageTypeSelectHandler } from "@saleor/pages/utils/handlers";
import { import {
createAttributeChangeHandler, createAttributeChangeHandler,
createAttributeFileChangeHandler,
createAttributeMultiChangeHandler createAttributeMultiChangeHandler
} from "@saleor/products/utils/handlers"; } from "@saleor/products/utils/handlers";
import getPublicationData from "@saleor/utils/data/getPublicationData"; import getPublicationData from "@saleor/utils/data/getPublicationData";
@ -21,9 +29,7 @@ import { mapMetadataItemToInput } from "@saleor/utils/maps";
import getMetadata from "@saleor/utils/metadata/getMetadata"; import getMetadata from "@saleor/utils/metadata/getMetadata";
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
import useRichText from "@saleor/utils/richText/useRichText"; import useRichText from "@saleor/utils/richText/useRichText";
import React from "react"; import React, { useEffect } from "react";
import { PageAttributeInput, PageAttributeInputData } from "../PageAttributes";
export interface PageFormData extends MetadataFormData { export interface PageFormData extends MetadataFormData {
isPublished: boolean; isPublished: boolean;
@ -35,7 +41,13 @@ export interface PageFormData extends MetadataFormData {
pageType: string; pageType: string;
} }
export interface PageData extends PageFormData { export interface PageData extends PageFormData {
attributes: PageAttributeInput[]; attributes: AttributeInput[];
content: OutputData;
}
export interface PageSubmitData extends PageFormData {
attributes: AttributeInput[];
attributesWithNewFileValue: FormsetData<null, File>;
content: OutputData; content: OutputData;
} }
@ -43,8 +55,9 @@ interface PageUpdateHandlers {
changeMetadata: FormChange; changeMetadata: FormChange;
changeContent: RichTextEditorChange; changeContent: RichTextEditorChange;
selectPageType: FormChange; selectPageType: FormChange;
changeAttribute: FormsetChange<string>; selectAttribute: FormsetChange<string>;
changeAttributeMulti: FormsetChange<string>; selectAttributeMulti: FormsetChange<string>;
selectAttributeFile: FormsetChange<File>;
} }
export interface UsePageUpdateFormResult { export interface UsePageUpdateFormResult {
change: FormChange; change: FormChange;
@ -72,16 +85,8 @@ function usePageForm(
const pageExists = page !== null; const pageExists = page !== null;
const attributesFromPage = React.useMemo( const attributes = useFormset(getAttributeInputFromPage(page));
() => getAttributeInputFromPage(page), const attributesWithNewFileValue = useFormset<null, File>([]);
[page]
);
const {
change: changeAttributeData,
data: attributes,
set: setAttributeData
} = useFormset<PageAttributeInputData>(attributesFromPage || []);
const form = useForm<PageFormData>({ const form = useForm<PageFormData>({
isPublished: page?.isPublished, isPublished: page?.isPublished,
@ -118,31 +123,46 @@ function usePageForm(
const changeMetadata = makeMetadataChangeHandler(handleChange); const changeMetadata = makeMetadataChangeHandler(handleChange);
const selectPageType = createPageTypeSelectHandler( const selectPageType = createPageTypeSelectHandler(
handleChange, handleChange,
setAttributeData, attributes.set,
setPageType, setPageType,
pageTypes pageTypes
); );
const changeAttribute = createAttributeChangeHandler( const handleAttributeChange = createAttributeChangeHandler(
changeAttributeData, attributes.change,
triggerChange triggerChange
); );
const changeAttributeMulti = createAttributeMultiChangeHandler( const handleAttributeMultiChange = createAttributeMultiChangeHandler(
changeAttributeData, attributes.change,
attributes, attributes.data,
triggerChange triggerChange
); );
const handleAttributeFileChange = createAttributeFileChangeHandler(
attributes.change,
attributesWithNewFileValue.data,
attributesWithNewFileValue.add,
attributesWithNewFileValue.change,
triggerChange
);
useEffect(() => {
attributesWithNewFileValue.set([]);
}, [page]);
// Need to make it function to always have content.current up to date // Need to make it function to always have content.current up to date
const getData = (): PageData => ({ const getData = (): PageData => ({
...form.data, ...form.data,
attributes, attributes: getAttributesDisplayData(
attributes.data,
attributesWithNewFileValue.data
),
content: content.current content: content.current
}); });
const getSubmitData = (): PageData => ({ const getSubmitData = (): PageSubmitData => ({
...getData(), ...getData(),
...getMetadata(form.data, isMetadataModified, isPrivateMetadataModified), ...getMetadata(form.data, isMetadataModified, isPrivateMetadataModified),
...getPublicationData(form.data) ...getPublicationData(form.data),
attributesWithNewFileValue: attributesWithNewFileValue.data
}); });
const submit = () => const submit = () =>
@ -154,10 +174,11 @@ function usePageForm(
change: handleChange, change: handleChange,
data: getData(), data: getData(),
handlers: { handlers: {
changeAttribute,
changeAttributeMulti,
changeContent, changeContent,
changeMetadata, changeMetadata,
selectAttribute: handleAttributeChange,
selectAttributeFile: handleAttributeFileChange,
selectAttributeMulti: handleAttributeMultiChange,
selectPageType selectPageType
}, },
hasChanged: changed, hasChanged: changed,

View file

@ -52,19 +52,22 @@ export const page: PageDetails_page = {
id: "QXR0cmlidXRlVmFsdWU6ODc=", id: "QXR0cmlidXRlVmFsdWU6ODc=",
name: "Suzanne Ellison", name: "Suzanne Ellison",
slug: "suzanne-ellison", slug: "suzanne-ellison",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6ODg=", id: "QXR0cmlidXRlVmFsdWU6ODg=",
name: "Dennis Perkins", name: "Dennis Perkins",
slug: "dennis-perkins", slug: "dennis-perkins",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6ODk=", id: "QXR0cmlidXRlVmFsdWU6ODk=",
name: "Dylan Lamb", name: "Dylan Lamb",
slug: "dylan-lamb", slug: "dylan-lamb",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
} }
], ],
__typename: "Attribute" __typename: "Attribute"
@ -74,7 +77,8 @@ export const page: PageDetails_page = {
id: "QXR0cmlidXRlVmFsdWU6ODk=", id: "QXR0cmlidXRlVmFsdWU6ODk=",
name: "Dylan Lamb", name: "Dylan Lamb",
slug: "dylan-lamb", slug: "dylan-lamb",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
} }
], ],
__typename: "SelectedAttribute" __typename: "SelectedAttribute"
@ -91,25 +95,29 @@ export const page: PageDetails_page = {
id: "QXR0cmlidXRlVmFsdWU6OTA=", id: "QXR0cmlidXRlVmFsdWU6OTA=",
name: "Security", name: "Security",
slug: "security", slug: "security",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6OTE=", id: "QXR0cmlidXRlVmFsdWU6OTE=",
name: "Support", name: "Support",
slug: "support", slug: "support",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6OTI=", id: "QXR0cmlidXRlVmFsdWU6OTI=",
name: "Medical", name: "Medical",
slug: "medical", slug: "medical",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6OTM=", id: "QXR0cmlidXRlVmFsdWU6OTM=",
name: "General", name: "General",
slug: "general", slug: "general",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
} }
], ],
__typename: "Attribute" __typename: "Attribute"
@ -119,7 +127,8 @@ export const page: PageDetails_page = {
id: "QXR0cmlidXRlVmFsdWU6OTA=", id: "QXR0cmlidXRlVmFsdWU6OTA=",
name: "Security", name: "Security",
slug: "security", slug: "security",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
} }
], ],
__typename: "SelectedAttribute" __typename: "SelectedAttribute"
@ -150,19 +159,22 @@ export const page: PageDetails_page = {
id: "QXR0cmlidXRlVmFsdWU6ODc=", id: "QXR0cmlidXRlVmFsdWU6ODc=",
name: "Suzanne Ellison", name: "Suzanne Ellison",
slug: "suzanne-ellison", slug: "suzanne-ellison",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6ODg=", id: "QXR0cmlidXRlVmFsdWU6ODg=",
name: "Dennis Perkins", name: "Dennis Perkins",
slug: "dennis-perkins", slug: "dennis-perkins",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6ODk=", id: "QXR0cmlidXRlVmFsdWU6ODk=",
name: "Dylan Lamb", name: "Dylan Lamb",
slug: "dylan-lamb", slug: "dylan-lamb",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
} }
], ],
__typename: "Attribute" __typename: "Attribute"
@ -177,25 +189,29 @@ export const page: PageDetails_page = {
id: "QXR0cmlidXRlVmFsdWU6OTA=", id: "QXR0cmlidXRlVmFsdWU6OTA=",
name: "Security", name: "Security",
slug: "security", slug: "security",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6OTE=", id: "QXR0cmlidXRlVmFsdWU6OTE=",
name: "Support", name: "Support",
slug: "support", slug: "support",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6OTI=", id: "QXR0cmlidXRlVmFsdWU6OTI=",
name: "Medical", name: "Medical",
slug: "medical", slug: "medical",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
}, },
{ {
id: "QXR0cmlidXRlVmFsdWU6OTM=", id: "QXR0cmlidXRlVmFsdWU6OTM=",
name: "General", name: "General",
slug: "general", slug: "general",
__typename: "AttributeValue" __typename: "AttributeValue",
file: null
} }
], ],
__typename: "Attribute" __typename: "Attribute"

View file

@ -3,6 +3,7 @@ import {
pageErrorWithAttributesFragment pageErrorWithAttributesFragment
} from "@saleor/fragments/errors"; } from "@saleor/fragments/errors";
import { pageDetailsFragment } from "@saleor/fragments/pages"; import { pageDetailsFragment } from "@saleor/fragments/pages";
import makeMutation from "@saleor/hooks/makeMutation";
import gql from "graphql-tag"; import gql from "graphql-tag";
import { TypedMutation } from "../mutations"; import { TypedMutation } from "../mutations";
@ -51,9 +52,10 @@ const pageUpdate = gql`
} }
} }
`; `;
export const TypedPageUpdate = TypedMutation<PageUpdate, PageUpdateVariables>( export const usePageUpdateMutation = makeMutation<
pageUpdate PageUpdate,
); PageUpdateVariables
>(pageUpdate);
const pageRemove = gql` const pageRemove = gql`
${pageErrorFragment} ${pageErrorFragment}
@ -65,9 +67,10 @@ const pageRemove = gql`
} }
} }
`; `;
export const TypedPageRemove = TypedMutation<PageRemove, PageRemoveVariables>( export const usePageRemoveMutation = makeMutation<
pageRemove PageRemove,
); PageRemoveVariables
>(pageRemove);
const pageBulkPublish = gql` const pageBulkPublish = gql`
mutation PageBulkPublish($ids: [ID]!, $isPublished: Boolean!) { mutation PageBulkPublish($ids: [ID]!, $isPublished: Boolean!) {

View file

@ -2,7 +2,6 @@ import { pageDetailsFragment, pageFragment } from "@saleor/fragments/pages";
import makeQuery from "@saleor/hooks/makeQuery"; import makeQuery from "@saleor/hooks/makeQuery";
import gql from "graphql-tag"; import gql from "graphql-tag";
import { TypedQuery } from "../queries";
import { PageDetails, PageDetailsVariables } from "./types/PageDetails"; import { PageDetails, PageDetailsVariables } from "./types/PageDetails";
import { PageList, PageListVariables } from "./types/PageList"; import { PageList, PageListVariables } from "./types/PageList";
@ -48,7 +47,6 @@ const pageDetails = gql`
} }
} }
`; `;
export const TypedPageDetailsQuery = TypedQuery< export const usePageDetailsQuery = makeQuery<PageDetails, PageDetailsVariables>(
PageDetails, pageDetails
PageDetailsVariables );
>(pageDetails);

View file

@ -16,11 +16,18 @@ export interface PageCreate_pageCreate_errors {
message: string | null; message: string | null;
} }
export interface PageCreate_pageCreate_page_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageCreate_pageCreate_page_attributes_attribute_values { export interface PageCreate_pageCreate_page_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageCreate_pageCreate_page_attributes_attribute_values_file | null;
} }
export interface PageCreate_pageCreate_page_attributes_attribute { export interface PageCreate_pageCreate_page_attributes_attribute {
@ -33,11 +40,18 @@ export interface PageCreate_pageCreate_page_attributes_attribute {
values: (PageCreate_pageCreate_page_attributes_attribute_values | null)[] | null; values: (PageCreate_pageCreate_page_attributes_attribute_values | null)[] | null;
} }
export interface PageCreate_pageCreate_page_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageCreate_pageCreate_page_attributes_values { export interface PageCreate_pageCreate_page_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageCreate_pageCreate_page_attributes_values_file | null;
} }
export interface PageCreate_pageCreate_page_attributes { export interface PageCreate_pageCreate_page_attributes {
@ -46,11 +60,18 @@ export interface PageCreate_pageCreate_page_attributes {
values: (PageCreate_pageCreate_page_attributes_values | null)[]; values: (PageCreate_pageCreate_page_attributes_values | null)[];
} }
export interface PageCreate_pageCreate_page_pageType_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageCreate_pageCreate_page_pageType_attributes_values { export interface PageCreate_pageCreate_page_pageType_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageCreate_pageCreate_page_pageType_attributes_values_file | null;
} }
export interface PageCreate_pageCreate_page_pageType_attributes { export interface PageCreate_pageCreate_page_pageType_attributes {

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// GraphQL query operation: PageDetails // GraphQL query operation: PageDetails
// ==================================================== // ====================================================
export interface PageDetails_page_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageDetails_page_attributes_attribute_values { export interface PageDetails_page_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageDetails_page_attributes_attribute_values_file | null;
} }
export interface PageDetails_page_attributes_attribute { export interface PageDetails_page_attributes_attribute {
@ -25,11 +32,18 @@ export interface PageDetails_page_attributes_attribute {
values: (PageDetails_page_attributes_attribute_values | null)[] | null; values: (PageDetails_page_attributes_attribute_values | null)[] | null;
} }
export interface PageDetails_page_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageDetails_page_attributes_values { export interface PageDetails_page_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageDetails_page_attributes_values_file | null;
} }
export interface PageDetails_page_attributes { export interface PageDetails_page_attributes {
@ -38,11 +52,18 @@ export interface PageDetails_page_attributes {
values: (PageDetails_page_attributes_values | null)[]; values: (PageDetails_page_attributes_values | null)[];
} }
export interface PageDetails_page_pageType_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageDetails_page_pageType_attributes_values { export interface PageDetails_page_pageType_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageDetails_page_pageType_attributes_values_file | null;
} }
export interface PageDetails_page_pageType_attributes { export interface PageDetails_page_pageType_attributes {

View file

@ -15,11 +15,18 @@ export interface PageUpdate_pageUpdate_errors {
attributes: string[] | null; attributes: string[] | null;
} }
export interface PageUpdate_pageUpdate_page_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageUpdate_pageUpdate_page_attributes_attribute_values { export interface PageUpdate_pageUpdate_page_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageUpdate_pageUpdate_page_attributes_attribute_values_file | null;
} }
export interface PageUpdate_pageUpdate_page_attributes_attribute { export interface PageUpdate_pageUpdate_page_attributes_attribute {
@ -32,11 +39,18 @@ export interface PageUpdate_pageUpdate_page_attributes_attribute {
values: (PageUpdate_pageUpdate_page_attributes_attribute_values | null)[] | null; values: (PageUpdate_pageUpdate_page_attributes_attribute_values | null)[] | null;
} }
export interface PageUpdate_pageUpdate_page_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageUpdate_pageUpdate_page_attributes_values { export interface PageUpdate_pageUpdate_page_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageUpdate_pageUpdate_page_attributes_values_file | null;
} }
export interface PageUpdate_pageUpdate_page_attributes { export interface PageUpdate_pageUpdate_page_attributes {
@ -45,11 +59,18 @@ export interface PageUpdate_pageUpdate_page_attributes {
values: (PageUpdate_pageUpdate_page_attributes_values | null)[]; values: (PageUpdate_pageUpdate_page_attributes_values | null)[];
} }
export interface PageUpdate_pageUpdate_page_pageType_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface PageUpdate_pageUpdate_page_pageType_attributes_values { export interface PageUpdate_pageUpdate_page_pageType_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: PageUpdate_pageUpdate_page_pageType_attributes_values_file | null;
} }
export interface PageUpdate_pageUpdate_page_pageType_attributes { export interface PageUpdate_pageUpdate_page_pageType_attributes {

View file

@ -1,4 +1,6 @@
import { PageAttributeInput } from "../components/PageAttributes"; import { AttributeInput } from "@saleor/components/Attributes";
import { FormsetData } from "@saleor/hooks/useFormset";
import { import {
PageDetails_page, PageDetails_page,
PageDetails_page_pageType PageDetails_page_pageType
@ -6,11 +8,12 @@ import {
export function getAttributeInputFromPage( export function getAttributeInputFromPage(
page: PageDetails_page page: PageDetails_page
): PageAttributeInput[] { ): AttributeInput[] {
return page?.attributes.map(attribute => ({ return page?.attributes.map(attribute => ({
data: { data: {
inputType: attribute.attribute.inputType, inputType: attribute.attribute.inputType,
isRequired: attribute.attribute.valueRequired, isRequired: attribute.attribute.valueRequired,
selectedValues: attribute.values,
values: attribute.attribute.values values: attribute.attribute.values
}, },
id: attribute.attribute.id, id: attribute.attribute.id,
@ -21,7 +24,7 @@ export function getAttributeInputFromPage(
export function getAttributeInputFromPageType( export function getAttributeInputFromPageType(
pageType: PageDetails_page_pageType pageType: PageDetails_page_pageType
): PageAttributeInput[] { ): AttributeInput[] {
return pageType?.attributes.map(attribute => ({ return pageType?.attributes.map(attribute => ({
data: { data: {
inputType: attribute.inputType, inputType: attribute.inputType,
@ -33,3 +36,23 @@ export function getAttributeInputFromPageType(
value: [] value: []
})); }));
} }
export const getAttributesDisplayData = (
attributes: AttributeInput[],
attributesWithNewFileValue: FormsetData<null, File>
) =>
attributes.map(attribute => {
const attributeWithNewFileValue = attributesWithNewFileValue.find(
attributeWithNewFile => attribute.id === attributeWithNewFile.id
);
if (attributeWithNewFileValue) {
return {
...attribute,
value: attributeWithNewFileValue?.value?.name
? [attributeWithNewFileValue.value.name]
: []
};
}
return attribute;
});

View file

@ -1,10 +1,10 @@
import { AttributeInputData } from "@saleor/components/Attributes";
import { FormsetData } from "@saleor/hooks/useFormset"; import { FormsetData } from "@saleor/hooks/useFormset";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { PageAttributeInputData } from "../components/PageAttributes";
import { createAttributeMultiChangeHandler } from "./handlers"; import { createAttributeMultiChangeHandler } from "./handlers";
const attributes: FormsetData<PageAttributeInputData, string[]> = [ const attributes: FormsetData<AttributeInputData, string[]> = [
{ {
data: { data: {
inputType: AttributeInputTypeEnum.DROPDOWN, inputType: AttributeInputTypeEnum.DROPDOWN,
@ -12,6 +12,7 @@ const attributes: FormsetData<PageAttributeInputData, string[]> = [
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-1", id: "attrv-1",
name: "Attribute 1 Value 1", name: "Attribute 1 Value 1",
slug: "attr-1-v-1" slug: "attr-1-v-1"
@ -29,18 +30,21 @@ const attributes: FormsetData<PageAttributeInputData, string[]> = [
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-2", id: "attrv-2",
name: "Attribute 2 Value 1", name: "Attribute 2 Value 1",
slug: "attr-2-v-1" slug: "attr-2-v-1"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-3", id: "attrv-3",
name: "Attribute 2 Value 2", name: "Attribute 2 Value 2",
slug: "attr-2-v-2" slug: "attr-2-v-2"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-4", id: "attrv-4",
name: "Attribute 2 Value 3", name: "Attribute 2 Value 3",
slug: "attr-2-v-3" slug: "attr-2-v-3"
@ -50,6 +54,28 @@ const attributes: FormsetData<PageAttributeInputData, string[]> = [
id: "attr-2", id: "attr-2",
label: "Attribute 2", label: "Attribute 2",
value: ["attr-2-v-3"] value: ["attr-2-v-3"]
},
{
data: {
inputType: AttributeInputTypeEnum.FILE,
isRequired: false,
values: [
{
__typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "gdghdgdhkkdae",
name: "File First Value",
slug: "file-first-value"
}
]
},
id: "ifudbgidfsb",
label: "File Attribute",
value: []
} }
]; ];

View file

@ -1,14 +1,14 @@
import { AttributeInputData } from "@saleor/components/Attributes";
import { FormChange } from "@saleor/hooks/useForm"; import { FormChange } from "@saleor/hooks/useForm";
import { FormsetChange, FormsetData } from "@saleor/hooks/useFormset"; import { FormsetChange, FormsetData } from "@saleor/hooks/useFormset";
import { toggle } from "@saleor/utils/lists"; import { toggle } from "@saleor/utils/lists";
import { PageAttributeInputData } from "../components/PageAttributes";
import { PageDetails_page_pageType } from "../types/PageDetails"; import { PageDetails_page_pageType } from "../types/PageDetails";
import { getAttributeInputFromPageType } from "./data"; import { getAttributeInputFromPageType } from "./data";
export function createPageTypeSelectHandler( export function createPageTypeSelectHandler(
change: FormChange, change: FormChange,
setAttributes: (data: FormsetData<PageAttributeInputData>) => void, setAttributes: (data: FormsetData<AttributeInputData>) => void,
setPageType: (pageType: PageDetails_page_pageType) => void, setPageType: (pageType: PageDetails_page_pageType) => void,
pageTypeChoiceList: PageDetails_page_pageType[] pageTypeChoiceList: PageDetails_page_pageType[]
): FormChange { ): FormChange {
@ -36,7 +36,7 @@ export function createAttributeChangeHandler(
export function createAttributeMultiChangeHandler( export function createAttributeMultiChangeHandler(
changeAttributeData: FormsetChange<string[]>, changeAttributeData: FormsetChange<string[]>,
attributes: FormsetData<PageAttributeInputData, string[]>, attributes: FormsetData<AttributeInputData, string[]>,
triggerChange: () => void triggerChange: () => void
): FormsetChange { ): FormsetChange {
return (attributeId: string, value: string) => { return (attributeId: string, value: string) => {

View file

@ -1,5 +1,11 @@
import { getAttributesAfterFileAttributesUpdate } from "@saleor/attributes/utils/data";
import {
handleUploadMultipleFiles,
prepareAttributesInput
} from "@saleor/attributes/utils/handlers";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import { useFileUploadMutation } from "@saleor/files/mutations";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import usePageTypeSearch from "@saleor/searches/usePageTypeSearch"; import usePageTypeSearch from "@saleor/searches/usePageTypeSearch";
@ -12,7 +18,7 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import PageDetailsPage from "../components/PageDetailsPage"; import PageDetailsPage from "../components/PageDetailsPage";
import { PageData } from "../components/PageDetailsPage/form"; import { PageSubmitData } from "../components/PageDetailsPage/form";
import { TypedPageCreate } from "../mutations"; import { TypedPageCreate } from "../mutations";
import { PageCreate as PageCreateData } from "../types/PageCreate"; import { PageCreate as PageCreateData } from "../types/PageCreate";
import { pageListUrl, pageUrl } from "../urls"; import { pageListUrl, pageUrl } from "../urls";
@ -36,6 +42,8 @@ export const PageCreate: React.FC<PageCreateProps> = () => {
variables: DEFAULT_INITIAL_SEARCH_DATA variables: DEFAULT_INITIAL_SEARCH_DATA
}); });
const [uploadFile, uploadFileOpts] = useFileUploadMutation({});
const handlePageCreate = (data: PageCreateData) => { const handlePageCreate = (data: PageCreateData) => {
if (data.pageCreate.errors.length === 0) { if (data.pageCreate.errors.length === 0) {
notify({ notify({
@ -51,14 +59,24 @@ export const PageCreate: React.FC<PageCreateProps> = () => {
return ( return (
<TypedPageCreate onCompleted={handlePageCreate}> <TypedPageCreate onCompleted={handlePageCreate}>
{(pageCreate, pageCreateOpts) => { {(pageCreate, pageCreateOpts) => {
const handleCreate = async (formData: PageData) => { const handleCreate = async (formData: PageSubmitData) => {
const uploadFilesResult = await handleUploadMultipleFiles(
formData.attributesWithNewFileValue,
variables => uploadFile({ variables })
);
const updatedFileAttributes = getAttributesAfterFileAttributesUpdate(
formData.attributesWithNewFileValue,
uploadFilesResult
);
const result = await pageCreate({ const result = await pageCreate({
variables: { variables: {
input: { input: {
attributes: formData.attributes.map(attribute => ({ attributes: prepareAttributesInput({
id: attribute.id, attributes: formData.attributes,
values: attribute.value updatedFileAttributes
})), }),
contentJson: JSON.stringify(formData.content), contentJson: JSON.stringify(formData.content),
isPublished: formData.isPublished, isPublished: formData.isPublished,
pageType: formData.pageType, pageType: formData.pageType,
@ -90,7 +108,7 @@ export const PageCreate: React.FC<PageCreateProps> = () => {
})} })}
/> />
<PageDetailsPage <PageDetailsPage
disabled={pageCreateOpts.loading} loading={pageCreateOpts.loading || uploadFileOpts.loading}
errors={pageCreateOpts.data?.pageCreate.errors || []} errors={pageCreateOpts.data?.pageCreate.errors || []}
saveButtonBarState={pageCreateOpts.status} saveButtonBarState={pageCreateOpts.status}
page={null} page={null}

View file

@ -1,6 +1,21 @@
import DialogContentText from "@material-ui/core/DialogContentText"; import DialogContentText from "@material-ui/core/DialogContentText";
import { useAttributeValueDeleteMutation } from "@saleor/attributes/mutations";
import {
getAttributesAfterFileAttributesUpdate,
mergeAttributeValueDeleteErrors,
mergeFileUploadErrors
} from "@saleor/attributes/utils/data";
import {
handleDeleteMultipleAttributeValues,
handleUploadMultipleFiles,
prepareAttributesInput
} from "@saleor/attributes/utils/handlers";
import ActionDialog from "@saleor/components/ActionDialog"; import ActionDialog from "@saleor/components/ActionDialog";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import { useFileUploadMutation } from "@saleor/files/mutations";
import { AttributeErrorFragment } from "@saleor/fragments/types/AttributeErrorFragment";
import { PageErrorFragment } from "@saleor/fragments/types/PageErrorFragment";
import { UploadErrorFragment } from "@saleor/fragments/types/UploadErrorFragment";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
@ -13,11 +28,11 @@ import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { getStringOrPlaceholder, maybe } from "../../misc"; import { getStringOrPlaceholder, maybe } from "../../misc";
import { PageInput } from "../../types/globalTypes"; import { AttributeValueInput, PageInput } from "../../types/globalTypes";
import PageDetailsPage from "../components/PageDetailsPage"; import PageDetailsPage from "../components/PageDetailsPage";
import { PageData } from "../components/PageDetailsPage/form"; import { PageData, PageSubmitData } from "../components/PageDetailsPage/form";
import { TypedPageRemove, TypedPageUpdate } from "../mutations"; import { usePageRemoveMutation, usePageUpdateMutation } from "../mutations";
import { TypedPageDetailsQuery } from "../queries"; import { usePageDetailsQuery } from "../queries";
import { PageRemove } from "../types/PageRemove"; import { PageRemove } from "../types/PageRemove";
import { pageListUrl, pageUrl, PageUrlQueryParams } from "../urls"; import { pageListUrl, pageUrl, PageUrlQueryParams } from "../urls";
@ -26,11 +41,14 @@ export interface PageDetailsProps {
params: PageUrlQueryParams; params: PageUrlQueryParams;
} }
const createPageInput = (data: PageData): PageInput => ({ const createPageInput = (
attributes: data.attributes.map(attribute => ({ data: PageData,
id: attribute.id, updatedFileAttributes: AttributeValueInput[]
values: attribute.value ): PageInput => ({
})), attributes: prepareAttributesInput({
attributes: data.attributes,
updatedFileAttributes
}),
contentJson: JSON.stringify(data.content), contentJson: JSON.stringify(data.content),
isPublished: data.isPublished, isPublished: data.isPublished,
publicationDate: data.publicationDate, publicationDate: data.publicationDate,
@ -49,96 +67,127 @@ export const PageDetails: React.FC<PageDetailsProps> = ({ id, params }) => {
const [updateMetadata] = useMetadataUpdate({}); const [updateMetadata] = useMetadataUpdate({});
const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const [updatePrivateMetadata] = usePrivateMetadataUpdate({});
const handlePageRemove = (data: PageRemove) => { const pageDetails = usePageDetailsQuery({
if (data.pageDelete.errors.length === 0) { variables: {
notify({ id
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
});
navigate(pageListUrl());
} }
});
const [uploadFile, uploadFileOpts] = useFileUploadMutation({});
const [pageUpdate, pageUpdateOpts] = usePageUpdateMutation({});
const [
deleteAttributeValue,
deleteAttributeValueOpts
] = useAttributeValueDeleteMutation({});
const [pageRemove, pageRemoveOpts] = usePageRemoveMutation({
onCompleted: (data: PageRemove) => {
if (data.pageDelete.errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage(commonMessages.savedChanges)
});
navigate(pageListUrl());
}
}
});
const handleUpdate = async (data: PageSubmitData) => {
let errors: Array<
AttributeErrorFragment | UploadErrorFragment | PageErrorFragment
> = [];
const uploadFilesResult = await handleUploadMultipleFiles(
data.attributesWithNewFileValue,
variables => uploadFile({ variables })
);
const deleteAttributeValuesResult = await handleDeleteMultipleAttributeValues(
data.attributesWithNewFileValue,
pageDetails?.data?.page?.attributes,
variables => deleteAttributeValue({ variables })
);
const updatedFileAttributes = getAttributesAfterFileAttributesUpdate(
data.attributesWithNewFileValue,
uploadFilesResult
);
const updateResult = await pageUpdate({
variables: {
id,
input: createPageInput(data, updatedFileAttributes)
}
});
errors = [
...errors,
...mergeFileUploadErrors(uploadFilesResult),
...mergeAttributeValueDeleteErrors(deleteAttributeValuesResult),
...updateResult.data.pageUpdate.errors
];
return errors;
}; };
const handleSubmit = createMetadataUpdateHandler(
pageDetails.data?.page,
handleUpdate,
variables => updateMetadata({ variables }),
variables => updatePrivateMetadata({ variables })
);
return ( return (
<TypedPageRemove variables={{ id }} onCompleted={handlePageRemove}> <>
{(pageRemove, pageRemoveOpts) => ( <WindowTitle title={maybe(() => pageDetails.data.page.title)} />
<TypedPageUpdate> <PageDetailsPage
{(pageUpdate, pageUpdateOpts) => ( loading={
<TypedPageDetailsQuery variables={{ id }}> pageDetails.loading ||
{pageDetails => { pageUpdateOpts.loading ||
const handleUpdate = async (data: PageData) => { uploadFileOpts.loading ||
const result = await pageUpdate({ deleteAttributeValueOpts.loading
variables: { }
id, errors={pageUpdateOpts.data?.pageUpdate.errors || []}
input: createPageInput(data) saveButtonBarState={pageUpdateOpts.status}
} page={pageDetails.data?.page}
}); onBack={() => navigate(pageListUrl())}
onRemove={() =>
return result.data.pageUpdate.errors; navigate(
}; pageUrl(id, {
action: "remove"
const handleSubmit = createMetadataUpdateHandler( })
pageDetails.data?.page, )
handleUpdate, }
variables => updateMetadata({ variables }), onSubmit={handleSubmit}
variables => updatePrivateMetadata({ variables }) />
); <ActionDialog
open={params.action === "remove"}
return ( confirmButtonState={pageRemoveOpts.status}
<> title={intl.formatMessage({
<WindowTitle defaultMessage: "Delete Page",
title={maybe(() => pageDetails.data.page.title)} description: "dialog header"
/> })}
<PageDetailsPage onClose={() => navigate(pageUrl(id))}
disabled={pageDetails.loading} onConfirm={() => pageRemove({ variables: { id } })}
errors={pageUpdateOpts.data?.pageUpdate.errors || []} variant="delete"
saveButtonBarState={pageUpdateOpts.status} >
page={pageDetails.data?.page} <DialogContentText>
onBack={() => navigate(pageListUrl())} <FormattedMessage
onRemove={() => defaultMessage="Are you sure you want to delete {title}?"
navigate( description="delete page"
pageUrl(id, { values={{
action: "remove" title: (
}) <strong>
) {getStringOrPlaceholder(pageDetails.data?.page?.title)}
} </strong>
onSubmit={handleSubmit} )
/> }}
<ActionDialog />
open={params.action === "remove"} </DialogContentText>
confirmButtonState={pageRemoveOpts.status} </ActionDialog>
title={intl.formatMessage({ </>
defaultMessage: "Delete Page",
description: "dialog header"
})}
onClose={() => navigate(pageUrl(id))}
onConfirm={pageRemove}
variant="delete"
>
<DialogContentText>
<FormattedMessage
defaultMessage="Are you sure you want to delete {title}?"
description="delete page"
values={{
title: (
<strong>
{getStringOrPlaceholder(
pageDetails.data?.page?.title
)}
</strong>
)
}}
/>
</DialogContentText>
</ActionDialog>
</>
);
}}
</TypedPageDetailsQuery>
)}
</TypedPageUpdate>
)}
</TypedPageRemove>
); );
}; };
PageDetails.displayName = "PageDetails"; PageDetails.displayName = "PageDetails";

View file

@ -23,6 +23,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI0",
name: "John Doe", name: "John Doe",
slug: "john-doe", slug: "john-doe",
@ -32,6 +33,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI1",
name: "Milionare Pirate", name: "Milionare Pirate",
slug: "milionare-pirate", slug: "milionare-pirate",
@ -53,6 +55,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE1",
name: "100g", name: "100g",
slug: "100g", slug: "100g",
@ -62,6 +65,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE2", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE2",
name: "250g", name: "250g",
slug: "250g", slug: "250g",
@ -71,6 +75,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE3", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE3",
name: "500g", name: "500g",
slug: "500g", slug: "500g",
@ -80,6 +85,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE4", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE4",
name: "1kg", name: "1kg",
slug: "1kg", slug: "1kg",
@ -101,6 +107,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjY=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjY=",
name: "Saleor", name: "Saleor",
slug: "saleor", slug: "saleor",
@ -122,6 +129,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIx", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIx",
name: "100g", name: "100g",
slug: "100g", slug: "100g",
@ -131,6 +139,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIy", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIy",
name: "250g", name: "250g",
slug: "250g", slug: "250g",
@ -140,6 +149,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIz", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIz",
name: "500g", name: "500g",
slug: "500g", slug: "500g",
@ -161,6 +171,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEz", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEz",
name: "Arabica", name: "Arabica",
slug: "arabica", slug: "arabica",
@ -170,6 +181,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE0",
name: "Robusta", name: "Robusta",
slug: "robusta", slug: "robusta",
@ -191,6 +203,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM=",
name: "Round", name: "Round",
slug: "round", slug: "round",
@ -200,6 +213,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjQ=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjQ=",
name: "V-Neck", name: "V-Neck",
slug: "v-neck", slug: "v-neck",
@ -209,6 +223,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjU=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjU=",
name: "Polo", name: "Polo",
slug: "polo", slug: "polo",
@ -230,6 +245,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE=",
name: "Blue", name: "Blue",
slug: "blue", slug: "blue",
@ -239,6 +255,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI=",
name: "White", name: "White",
slug: "white", slug: "white",
@ -260,6 +277,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMw", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMw",
name: "Soft", name: "Soft",
slug: "soft", slug: "soft",
@ -269,6 +287,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMx", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMx",
name: "Hard", name: "Hard",
slug: "hard", slug: "hard",
@ -278,6 +297,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMy", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMy",
name: "Middle soft", name: "Middle soft",
slug: "middle-soft", slug: "middle-soft",
@ -287,6 +307,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMz", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjMz",
name: "Middle hard", name: "Middle hard",
slug: "middle-hard", slug: "middle-hard",
@ -296,6 +317,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM0", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM0",
name: "Middle", name: "Middle",
slug: "middle", slug: "middle",
@ -305,6 +327,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM1", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjM1",
name: "Very hard", name: "Very hard",
slug: "very-hard", slug: "very-hard",
@ -326,6 +349,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE5", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjE5",
name: "Sour", name: "Sour",
slug: "sour", slug: "sour",
@ -335,6 +359,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIw", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjIw",
name: "Sweet", name: "Sweet",
slug: "sweet", slug: "sweet",
@ -356,6 +381,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI4", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI4",
name: "English", name: "English",
slug: "english", slug: "english",
@ -365,6 +391,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI5", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI5",
name: "Pirate", name: "Pirate",
slug: "pirate", slug: "pirate",
@ -386,6 +413,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI2", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI2",
name: "Mirumee Press", name: "Mirumee Press",
slug: "mirumee-press", slug: "mirumee-press",
@ -395,6 +423,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI3", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjI3",
name: "Saleor Publishing", name: "Saleor Publishing",
slug: "saleor-publishing", slug: "saleor-publishing",
@ -416,6 +445,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
values: [ values: [
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjc=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjc=",
name: "XS", name: "XS",
slug: "xs", slug: "xs",
@ -425,6 +455,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjg=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjg=",
name: "S", name: "S",
slug: "s", slug: "s",
@ -434,6 +465,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjk=", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjk=",
name: "M", name: "M",
slug: "m", slug: "m",
@ -443,6 +475,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEw", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEw",
name: "L", name: "L",
slug: "l", slug: "l",
@ -452,6 +485,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEx", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEx",
name: "XL", name: "XL",
slug: "xl", slug: "xl",
@ -461,6 +495,7 @@ export const attributes: SearchProductTypes_search_edges_node_productAttributes[
}, },
{ {
__typename: "AttributeValue" as "AttributeValue", __typename: "AttributeValue" as "AttributeValue",
file: null,
id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEy", id: "UHJvZHVjdEF0dHJpYnV0ZVZhbHVlOjEy",
name: "XXL", name: "XXL",
slug: "xxl", slug: "xxl",

View file

@ -1,2 +0,0 @@
export { default } from "./ProductAttributes";
export * from "./ProductAttributes";

View file

@ -1,6 +1,7 @@
import { ChannelData } from "@saleor/channels/utils"; import { ChannelData } from "@saleor/channels/utils";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import { AvailabilityCard } from "@saleor/components/AvailabilityCard"; import Attributes from "@saleor/components/Attributes";
import AvailabilityCard from "@saleor/components/AvailabilityCard";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
@ -25,7 +26,6 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { FetchMoreProps } from "../../../types"; import { FetchMoreProps } from "../../../types";
import ProductAttributes from "../ProductAttributes";
import ProductDetailsForm from "../ProductDetailsForm"; import ProductDetailsForm from "../ProductDetailsForm";
import ProductOrganization from "../ProductOrganization"; import ProductOrganization from "../ProductOrganization";
import ProductShipping from "../ProductShipping/ProductShipping"; import ProductShipping from "../ProductShipping/ProductShipping";
@ -43,7 +43,7 @@ interface ProductCreatePageProps {
currentChannels: ChannelData[]; currentChannels: ChannelData[];
collections: SearchCollections_search_edges_node[]; collections: SearchCollections_search_edges_node[];
categories: SearchCategories_search_edges_node[]; categories: SearchCategories_search_edges_node[];
disabled: boolean; loading: boolean;
fetchMoreCategories: FetchMoreProps; fetchMoreCategories: FetchMoreProps;
fetchMoreCollections: FetchMoreProps; fetchMoreCollections: FetchMoreProps;
fetchMoreProductTypes: FetchMoreProps; fetchMoreProductTypes: FetchMoreProps;
@ -68,7 +68,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
allChannelsCount, allChannelsCount,
channelsErrors, channelsErrors,
currentChannels, currentChannels,
disabled, loading,
categories: categoryChoiceList, categories: categoryChoiceList,
collections: collectionChoiceList, collections: collectionChoiceList,
errors, errors,
@ -153,19 +153,21 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
<div> <div>
<ProductDetailsForm <ProductDetailsForm
data={data} data={data}
disabled={disabled} disabled={loading}
errors={errors} errors={errors}
onChange={change} onChange={change}
onDescriptionChange={handlers.changeDescription} onDescriptionChange={handlers.changeDescription}
/> />
<CardSpacer /> <CardSpacer />
{data.attributes.length > 0 && ( {data.attributes.length > 0 && (
<ProductAttributes <Attributes
attributes={data.attributes} attributes={data.attributes}
disabled={disabled} loading={loading}
disabled={loading}
errors={errors} errors={errors}
onChange={handlers.selectAttribute} onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple} onMultiChange={handlers.selectAttributeMultiple}
onFileChange={handlers.selectAttributeFile}
/> />
)} )}
<CardSpacer /> <CardSpacer />
@ -173,7 +175,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
<> <>
<ProductShipping <ProductShipping
data={data} data={data}
disabled={disabled} disabled={loading}
errors={errors} errors={errors}
weightUnit={weightUnit} weightUnit={weightUnit}
onChange={change} onChange={change}
@ -182,13 +184,13 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
<ProductVariantPrice <ProductVariantPrice
ProductVariantChannelListings={data.channelListings} ProductVariantChannelListings={data.channelListings}
errors={channelsErrors} errors={channelsErrors}
loading={disabled} loading={loading}
onChange={handlers.changeChannelPrice} onChange={handlers.changeChannelPrice}
/> />
<CardSpacer /> <CardSpacer />
<ProductStocks <ProductStocks
data={data} data={data}
disabled={disabled} disabled={loading}
hasVariants={false} hasVariants={false}
onFormDataChange={change} onFormDataChange={change}
errors={errors} errors={errors}
@ -214,7 +216,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
titlePlaceholder={data.name} titlePlaceholder={data.name}
description={data.seoDescription} description={data.seoDescription}
descriptionPlaceholder={data.seoTitle} descriptionPlaceholder={data.seoTitle}
loading={disabled} loading={loading}
onChange={change} onChange={change}
/> />
<CardSpacer /> <CardSpacer />
@ -227,7 +229,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
categoryInputDisplayValue={selectedCategory} categoryInputDisplayValue={selectedCategory}
collections={collections} collections={collections}
data={data} data={data}
disabled={disabled} disabled={loading}
errors={errors} errors={errors}
fetchCategories={fetchCategories} fetchCategories={fetchCategories}
fetchCollections={fetchCollections} fetchCollections={fetchCollections}
@ -260,14 +262,14 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
selectedChannelsCount={data.channelListings.length} selectedChannelsCount={data.channelListings.length}
allChannelsCount={allChannelsCount} allChannelsCount={allChannelsCount}
channels={data.channelListings} channels={data.channelListings}
disabled={disabled} disabled={loading}
onChange={handlers.changeChannels} onChange={handlers.changeChannels}
openModal={openChannelsModal} openModal={openChannelsModal}
/> />
<CardSpacer /> <CardSpacer />
<ProductTaxes <ProductTaxes
data={data} data={data}
disabled={disabled} disabled={loading}
onChange={change} onChange={change}
onTaxTypeChange={handlers.selectTaxRate} onTaxTypeChange={handlers.selectTaxRate}
selectedTaxTypeDisplayName={selectedTaxType} selectedTaxTypeDisplayName={selectedTaxType}
@ -279,7 +281,7 @@ export const ProductCreatePage: React.FC<ProductCreatePageProps> = ({
onCancel={onBack} onCancel={onBack}
onSave={submit} onSave={submit}
state={saveButtonBarState} state={saveButtonBarState}
disabled={disabled || !onSubmit || formDisabled || !hasChanged} disabled={loading || !onSubmit || formDisabled || !hasChanged}
/> />
</Container> </Container>
); );

View file

@ -1,18 +1,27 @@
import { OutputData } from "@editorjs/editorjs"; import { OutputData } from "@editorjs/editorjs";
import { ChannelData, ChannelPriceArgs } from "@saleor/channels/utils"; import { ChannelData, ChannelPriceArgs } from "@saleor/channels/utils";
import {
AttributeInput,
AttributeInputData
} from "@saleor/components/Attributes";
import { MetadataFormData } from "@saleor/components/Metadata"; import { MetadataFormData } from "@saleor/components/Metadata";
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
import { RichTextEditorChange } from "@saleor/components/RichTextEditor"; import { RichTextEditorChange } from "@saleor/components/RichTextEditor";
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
import useForm, { FormChange } from "@saleor/hooks/useForm"; import useForm, { FormChange } from "@saleor/hooks/useForm";
import useFormset, { FormsetChange } from "@saleor/hooks/useFormset"; import useFormset, {
FormsetChange,
FormsetData
} from "@saleor/hooks/useFormset";
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { import {
getAttributeInputFromProductType, getAttributeInputFromProductType,
getAttributesDisplayData,
ProductType ProductType
} from "@saleor/products/utils/data"; } from "@saleor/products/utils/data";
import { import {
createAttributeChangeHandler, createAttributeChangeHandler,
createAttributeFileChangeHandler,
createAttributeMultiChangeHandler, createAttributeMultiChangeHandler,
createChannelsChangeHandler, createChannelsChangeHandler,
createChannelsPriceChangeHandler, createChannelsPriceChangeHandler,
@ -30,10 +39,6 @@ import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTr
import useRichText from "@saleor/utils/richText/useRichText"; import useRichText from "@saleor/utils/richText/useRichText";
import React from "react"; import React from "react";
import {
ProductAttributeInput,
ProductAttributeInputData
} from "../ProductAttributes";
import { ProductStockInput } from "../ProductStocks"; import { ProductStockInput } from "../ProductStocks";
export interface ProductCreateFormData extends MetadataFormData { export interface ProductCreateFormData extends MetadataFormData {
@ -57,7 +62,8 @@ export interface ProductCreateFormData extends MetadataFormData {
weight: string; weight: string;
} }
export interface ProductCreateData extends ProductCreateFormData { export interface ProductCreateData extends ProductCreateFormData {
attributes: ProductAttributeInput[]; attributes: AttributeInput[];
attributesWithNewFileValue: FormsetData<null, File>;
stocks: ProductStockInput[]; stocks: ProductStockInput[];
} }
@ -82,6 +88,7 @@ interface ProductCreateHandlers
data: Omit<ChannelData, "name" | "price" | "currency" | "id"> data: Omit<ChannelData, "name" | "price" | "currency" | "id">
) => void ) => void
>, >,
Record<"selectAttributeFile", FormsetChange<File>>,
Record<"addStock" | "deleteStock", (id: string) => void> { Record<"addStock" | "deleteStock", (id: string) => void> {
changeDescription: RichTextEditorChange; changeDescription: RichTextEditorChange;
} }
@ -159,11 +166,12 @@ function useProductCreateForm(
...initial, ...initial,
...defaultInitialFormData ...defaultInitialFormData
}); });
const attributes = useFormset<ProductAttributeInputData>( const attributes = useFormset<AttributeInputData>(
initial?.productType initial?.productType
? getAttributeInputFromProductType(initialProductType) ? getAttributeInputFromProductType(initialProductType)
: [] : []
); );
const attributesWithNewFileValue = useFormset<null, File>([]);
const stocks = useFormset<null, string>([]); const stocks = useFormset<null, string>([]);
const [productType, setProductType] = useStateFromProps<ProductType>( const [productType, setProductType] = useStateFromProps<ProductType>(
initialProductType || null initialProductType || null
@ -201,6 +209,13 @@ function useProductCreateForm(
attributes.data, attributes.data,
triggerChange triggerChange
); );
const handleAttributeFileChange = createAttributeFileChangeHandler(
attributes.change,
attributesWithNewFileValue.data,
attributesWithNewFileValue.add,
attributesWithNewFileValue.change,
triggerChange
);
const handleProductTypeSelect = createProductTypeSelectHandler( const handleProductTypeSelect = createProductTypeSelectHandler(
attributes.set, attributes.set,
setProductType, setProductType,
@ -243,7 +258,11 @@ function useProductCreateForm(
const getData = (): ProductCreateData => ({ const getData = (): ProductCreateData => ({
...form.data, ...form.data,
attributes: attributes.data, attributes: getAttributesDisplayData(
attributes.data,
attributesWithNewFileValue.data
),
attributesWithNewFileValue: attributesWithNewFileValue.data,
description: description.current, description: description.current,
productType, productType,
stocks: stocks.data stocks: stocks.data
@ -276,6 +295,7 @@ function useProductCreateForm(
changeStock: handleStockChange, changeStock: handleStockChange,
deleteStock: handleStockDelete, deleteStock: handleStockDelete,
selectAttribute: handleAttributeChange, selectAttribute: handleAttributeChange,
selectAttributeFile: handleAttributeFileChange,
selectAttributeMultiple: handleAttributeMultiChange, selectAttributeMultiple: handleAttributeMultiChange,
selectCategory: handleCategorySelect, selectCategory: handleCategorySelect,
selectCollection: handleCollectionSelect, selectCollection: handleCollectionSelect,

View file

@ -67,7 +67,7 @@ const props: ProductUpdatePageProps = {
const selectors = { const selectors = {
dropdown: `[data-test="autocomplete-dropdown"]`, dropdown: `[data-test="autocomplete-dropdown"]`,
empty: `[data-test-type="empty"]`, empty: `[data-test-type="empty"]`,
input: `[data-test="product-attribute-value"] input` input: `[data-test="attribute-value"] input`
}; };
describe("Product details page", () => { describe("Product details page", () => {

View file

@ -1,7 +1,8 @@
import { OutputData } from "@editorjs/editorjs"; import { OutputData } from "@editorjs/editorjs";
import { ChannelData } from "@saleor/channels/utils"; import { ChannelData } from "@saleor/channels/utils";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import { AvailabilityCard } from "@saleor/components/AvailabilityCard"; import Attributes, { AttributeInput } from "@saleor/components/Attributes";
import AvailabilityCard from "@saleor/components/AvailabilityCard";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
@ -16,6 +17,7 @@ import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/Prod
import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment"; import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment";
import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { SubmitPromise } from "@saleor/hooks/useForm"; import { SubmitPromise } from "@saleor/hooks/useForm";
import { FormsetData } from "@saleor/hooks/useFormset";
import useStateFromProps from "@saleor/hooks/useStateFromProps"; import useStateFromProps from "@saleor/hooks/useStateFromProps";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
@ -37,7 +39,6 @@ import {
ProductDetails_product_variants ProductDetails_product_variants
} from "../../types/ProductDetails"; } from "../../types/ProductDetails";
import { getChoices, ProductUpdatePageFormData } from "../../utils/data"; import { getChoices, ProductUpdatePageFormData } from "../../utils/data";
import ProductAttributes, { ProductAttributeInput } from "../ProductAttributes";
import ProductDetailsForm from "../ProductDetailsForm"; import ProductDetailsForm from "../ProductDetailsForm";
import ProductImages from "../ProductImages"; import ProductImages from "../ProductImages";
import ProductOrganization from "../ProductOrganization"; import ProductOrganization from "../ProductOrganization";
@ -92,7 +93,8 @@ export interface ProductUpdatePageSubmitData
extends ProductUpdatePageFormData, extends ProductUpdatePageFormData,
ChannelProps { ChannelProps {
addStocks: ProductStockInput[]; addStocks: ProductStockInput[];
attributes: ProductAttributeInput[]; attributes: AttributeInput[];
attributesWithNewFileValue: FormsetData<null, File>;
collections: string[]; collections: string[];
description: OutputData; description: OutputData;
removeStocks: string[]; removeStocks: string[];
@ -217,12 +219,14 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
/> />
<CardSpacer /> <CardSpacer />
{data.attributes.length > 0 && ( {data.attributes.length > 0 && (
<ProductAttributes <Attributes
attributes={data.attributes} attributes={data.attributes}
errors={errors} errors={errors}
loading={disabled}
disabled={disabled} disabled={disabled}
onChange={handlers.selectAttribute} onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple} onMultiChange={handlers.selectAttributeMultiple}
onFileChange={handlers.selectAttributeFile}
/> />
)} )}
<CardSpacer /> <CardSpacer />

View file

@ -1,22 +1,26 @@
import { OutputData } from "@editorjs/editorjs"; import { OutputData } from "@editorjs/editorjs";
import { ChannelData, ChannelPriceArgs } from "@saleor/channels/utils"; import { ChannelData, ChannelPriceArgs } from "@saleor/channels/utils";
import { AttributeInput } from "@saleor/components/Attributes";
import { MetadataFormData } from "@saleor/components/Metadata"; import { MetadataFormData } from "@saleor/components/Metadata";
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
import { RichTextEditorChange } from "@saleor/components/RichTextEditor"; import { RichTextEditorChange } from "@saleor/components/RichTextEditor";
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm"; import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
import useFormset, { import useFormset, {
FormsetAtomicData,
FormsetChange, FormsetChange,
FormsetData FormsetData
} from "@saleor/hooks/useFormset"; } from "@saleor/hooks/useFormset";
import { ProductDetails_product } from "@saleor/products/types/ProductDetails"; import { ProductDetails_product } from "@saleor/products/types/ProductDetails";
import { import {
getAttributeInputFromProduct, getAttributeInputFromProduct,
getAttributesDisplayData,
getProductUpdatePageFormData, getProductUpdatePageFormData,
getStockInputFromProduct getStockInputFromProduct
} from "@saleor/products/utils/data"; } from "@saleor/products/utils/data";
import { import {
createAttributeChangeHandler, createAttributeChangeHandler,
createAttributeFileChangeHandler,
createAttributeMultiChangeHandler, createAttributeMultiChangeHandler,
createChannelsChangeHandler, createChannelsChangeHandler,
createChannelsPriceChangeHandler createChannelsPriceChangeHandler
@ -33,9 +37,8 @@ import getMetadata from "@saleor/utils/metadata/getMetadata";
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
import useRichText from "@saleor/utils/richText/useRichText"; import useRichText from "@saleor/utils/richText/useRichText";
import { diff } from "fast-array-diff"; import { diff } from "fast-array-diff";
import React from "react"; import React, { useEffect } from "react";
import { ProductAttributeInput } from "../ProductAttributes";
import { ProductStockFormsetData, ProductStockInput } from "../ProductStocks"; import { ProductStockFormsetData, ProductStockInput } from "../ProductStocks";
export interface ProductUpdateFormData extends MetadataFormData { export interface ProductUpdateFormData extends MetadataFormData {
@ -55,13 +58,26 @@ export interface ProductUpdateFormData extends MetadataFormData {
trackInventory: boolean; trackInventory: boolean;
weight: string; weight: string;
} }
export interface FileAttributeInputData {
attributeId: string;
file: File;
}
export type FileAttributeInput = FormsetAtomicData<
FileAttributeInputData,
string[]
>;
export interface FileAttributesSubmitData {
fileAttributes: FileAttributeInput[];
}
export interface ProductUpdateData extends ProductUpdateFormData { export interface ProductUpdateData extends ProductUpdateFormData {
attributes: ProductAttributeInput[]; attributes: AttributeInput[];
description: OutputData; description: OutputData;
stocks: ProductStockInput[]; stocks: ProductStockInput[];
} }
export interface ProductUpdateSubmitData extends ProductUpdateFormData { export interface ProductUpdateSubmitData extends ProductUpdateFormData {
attributes: ProductAttributeInput[]; attributes: AttributeInput[];
attributesWithNewFileValue: FormsetData<null, File>;
collections: string[]; collections: string[];
description: OutputData; description: OutputData;
addStocks: ProductStockInput[]; addStocks: ProductStockInput[];
@ -89,6 +105,7 @@ interface ProductUpdateHandlers
data: Omit<ChannelData, "name" | "price" | "currency" | "id"> data: Omit<ChannelData, "name" | "price" | "currency" | "id">
) => void ) => void
>, >,
Record<"selectAttributeFile", FormsetChange<File>>,
Record<"addStock" | "deleteStock", (id: string) => void> { Record<"addStock" | "deleteStock", (id: string) => void> {
changeDescription: RichTextEditorChange; changeDescription: RichTextEditorChange;
} }
@ -165,6 +182,7 @@ function useProductUpdateForm(
) )
); );
const attributes = useFormset(getAttributeInputFromProduct(product)); const attributes = useFormset(getAttributeInputFromProduct(product));
const attributesWithNewFileValue = useFormset<null, File>([]);
const stocks = useFormset(getStockInputFromProduct(product)); const stocks = useFormset(getStockInputFromProduct(product));
const [description, changeDescription] = useRichText({ const [description, changeDescription] = useRichText({
initial: product?.descriptionJson, initial: product?.descriptionJson,
@ -201,6 +219,13 @@ function useProductUpdateForm(
attributes.data, attributes.data,
triggerChange triggerChange
); );
const handleAttributeFileChange = createAttributeFileChangeHandler(
attributes.change,
attributesWithNewFileValue.data,
attributesWithNewFileValue.add,
attributesWithNewFileValue.change,
triggerChange
);
const handleStockChange: FormsetChange<string> = (id, value) => { const handleStockChange: FormsetChange<string> = (id, value) => {
triggerChange(); triggerChange();
stocks.change(id, value); stocks.change(id, value);
@ -235,9 +260,16 @@ function useProductUpdateForm(
triggerChange triggerChange
); );
useEffect(() => {
attributesWithNewFileValue.set([]);
}, [product]);
const data: ProductUpdateData = { const data: ProductUpdateData = {
...form.data, ...form.data,
attributes: attributes.data, attributes: getAttributesDisplayData(
attributes.data,
attributesWithNewFileValue.data
),
description: description.current, description: description.current,
stocks: stocks.data stocks: stocks.data
}; };
@ -248,10 +280,12 @@ function useProductUpdateForm(
...getMetadata(data, isMetadataModified, isPrivateMetadataModified), ...getMetadata(data, isMetadataModified, isPrivateMetadataModified),
addStocks: [], addStocks: [],
attributes: attributes.data, attributes: attributes.data,
attributesWithNewFileValue: attributesWithNewFileValue.data,
description: description.current description: description.current
}); });
const submit = () => handleFormSubmit(getSubmitData(), onSubmit, setChanged); const submit = async () =>
handleFormSubmit(getSubmitData(), onSubmit, setChanged);
const disabled = const disabled =
!opts.hasVariants && !opts.hasVariants &&
@ -274,6 +308,7 @@ function useProductUpdateForm(
changeStock: handleStockChange, changeStock: handleStockChange,
deleteStock: handleStockDelete, deleteStock: handleStockDelete,
selectAttribute: handleAttributeChange, selectAttribute: handleAttributeChange,
selectAttributeFile: handleAttributeFileChange,
selectAttributeMultiple: handleAttributeMultiChange, selectAttributeMultiple: handleAttributeMultiChange,
selectCategory: handleCategorySelect, selectCategory: handleCategorySelect,
selectCollection: handleCollectionSelect, selectCollection: handleCollectionSelect,

View file

@ -9,7 +9,10 @@ import SingleAutocompleteSelectField, {
} from "@saleor/components/SingleAutocompleteSelectField"; } from "@saleor/components/SingleAutocompleteSelectField";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment";
import { ProductVariant_attributes_attribute_values } from "@saleor/fragments/types/ProductVariant"; import {
ProductVariant_nonSelectionAttributes_attribute_values,
ProductVariant_selectionAttributes_attribute_values
} from "@saleor/fragments/types/ProductVariant";
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { commonMessages } from "@saleor/intl"; import { commonMessages } from "@saleor/intl";
import { getProductVariantAttributeErrorMessage } from "@saleor/utils/errors/product"; import { getProductVariantAttributeErrorMessage } from "@saleor/utils/errors/product";
@ -17,7 +20,10 @@ import React from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
export interface VariantAttributeInputData { export interface VariantAttributeInputData {
values: ProductVariant_attributes_attribute_values[]; values: Array<
| ProductVariant_selectionAttributes_attribute_values
| ProductVariant_nonSelectionAttributes_attribute_values
>;
} }
export type VariantAttributeInput = FormsetAtomicData< export type VariantAttributeInput = FormsetAtomicData<
VariantAttributeInputData, VariantAttributeInputData,

View file

@ -1,5 +1,8 @@
import { ChannelPriceData } from "@saleor/channels/utils"; import { ChannelPriceData } from "@saleor/channels/utils";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import Attributes, {
VariantAttributeScope
} from "@saleor/components/Attributes";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
@ -12,16 +15,34 @@ import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/Prod
import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses"; import { SearchWarehouses_search_edges_node } from "@saleor/searches/types/SearchWarehouses";
import { ReorderAction } from "@saleor/types"; import { ReorderAction } from "@saleor/types";
import React from "react"; import React from "react";
import { useIntl } from "react-intl"; import { defineMessages, useIntl } from "react-intl";
import { ProductVariantCreateData_product } from "../../types/ProductVariantCreateData"; import { ProductVariantCreateData_product } from "../../types/ProductVariantCreateData";
import ProductShipping from "../ProductShipping/ProductShipping"; import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks from "../ProductStocks"; import ProductStocks from "../ProductStocks";
import ProductVariantAttributes from "../ProductVariantAttributes";
import ProductVariantNavigation from "../ProductVariantNavigation"; import ProductVariantNavigation from "../ProductVariantNavigation";
import ProductVariantPrice from "../ProductVariantPrice"; import ProductVariantPrice from "../ProductVariantPrice";
import ProductVariantCreateForm, { ProductVariantCreateData } from "./form"; import ProductVariantCreateForm, { ProductVariantCreateData } from "./form";
const messages = defineMessages({
attributesHeader: {
defaultMessage: "Variant Attributes",
description: "attributes, section header"
},
attributesSelectionHeader: {
defaultMessage: "Variant Selection Attributes",
description: "attributes, section header"
},
deleteVariant: {
defaultMessage: "Delete Variant",
description: "button"
},
saveVariant: {
defaultMessage: "Save variant",
description: "button"
}
});
interface ProductVariantCreatePageProps { interface ProductVariantCreatePageProps {
channels: ChannelPriceData[]; channels: ChannelPriceData[];
channelErrors: ProductChannelListingErrorFragment[] | undefined; channelErrors: ProductChannelListingErrorFragment[] | undefined;
@ -89,11 +110,34 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
/> />
</div> </div>
<div> <div>
<ProductVariantAttributes <Attributes
attributes={data.attributes} title={intl.formatMessage(messages.attributesHeader)}
attributes={data.attributes.filter(
attribute =>
attribute.data.variantAttributeScope ===
VariantAttributeScope.NOT_VARIANT_SELECTION
)}
loading={disabled}
disabled={disabled} disabled={disabled}
errors={errors} errors={errors}
onChange={handlers.selectAttribute} onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple}
onFileChange={handlers.selectAttributeFile}
/>
<CardSpacer />
<Attributes
title={intl.formatMessage(messages.attributesSelectionHeader)}
attributes={data.attributes.filter(
attribute =>
attribute.data.variantAttributeScope ===
VariantAttributeScope.VARIANT_SELECTION
)}
loading={disabled}
disabled={disabled}
errors={errors}
onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple}
onFileChange={handlers.selectAttributeFile}
/> />
<CardSpacer /> <CardSpacer />
<ProductShipping <ProductShipping
@ -136,14 +180,8 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = ({
<SaveButtonBar <SaveButtonBar
disabled={disabled || formDisabled || !onSubmit || !hasChanged} disabled={disabled || formDisabled || !onSubmit || !hasChanged}
labels={{ labels={{
delete: intl.formatMessage({ delete: intl.formatMessage(messages.deleteVariant),
defaultMessage: "Delete Variant", save: intl.formatMessage(messages.saveVariant)
description: "button"
}),
save: intl.formatMessage({
defaultMessage: "Save variant",
description: "button"
})
}} }}
state={saveButtonBarState} state={saveButtonBarState}
onCancel={onBack} onCancel={onBack}

View file

@ -1,4 +1,5 @@
import { ChannelPriceData, IChannelPriceArgs } from "@saleor/channels/utils"; import { ChannelPriceData, IChannelPriceArgs } from "@saleor/channels/utils";
import { AttributeInput } from "@saleor/components/Attributes";
import { MetadataFormData } from "@saleor/components/Metadata"; import { MetadataFormData } from "@saleor/components/Metadata";
import useForm, { FormChange } from "@saleor/hooks/useForm"; import useForm, { FormChange } from "@saleor/hooks/useForm";
import useFormset, { import useFormset, {
@ -6,8 +7,18 @@ import useFormset, {
FormsetData FormsetData
} from "@saleor/hooks/useFormset"; } from "@saleor/hooks/useFormset";
import { ProductVariantCreateData_product } from "@saleor/products/types/ProductVariantCreateData"; import { ProductVariantCreateData_product } from "@saleor/products/types/ProductVariantCreateData";
import { getVariantAttributeInputFromProduct } from "@saleor/products/utils/data"; import {
import { getChannelsInput } from "@saleor/products/utils/handlers"; getAttributesDisplayData,
getVariantAttributeInputFromProduct
} from "@saleor/products/utils/data";
import {
createAttributeFileChangeHandler,
getChannelsInput
} from "@saleor/products/utils/handlers";
import {
createAttributeChangeHandler,
createAttributeMultiChangeHandler
} from "@saleor/products/utils/handlers";
import { import {
validateCostPrice, validateCostPrice,
validatePrice validatePrice
@ -17,7 +28,6 @@ import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTr
import React from "react"; import React from "react";
import { ProductStockInput } from "../ProductStocks"; import { ProductStockInput } from "../ProductStocks";
import { VariantAttributeInputData } from "../ProductVariantAttributes";
export interface ProductVariantCreateFormData extends MetadataFormData { export interface ProductVariantCreateFormData extends MetadataFormData {
sku: string; sku: string;
@ -25,8 +35,9 @@ export interface ProductVariantCreateFormData extends MetadataFormData {
weight: string; weight: string;
} }
export interface ProductVariantCreateData extends ProductVariantCreateFormData { export interface ProductVariantCreateData extends ProductVariantCreateFormData {
attributes: FormsetData<VariantAttributeInputData, string>;
channelListings: FormsetData<ChannelPriceData, IChannelPriceArgs>; channelListings: FormsetData<ChannelPriceData, IChannelPriceArgs>;
attributes: AttributeInput[];
attributesWithNewFileValue: FormsetData<null, File>;
stocks: ProductStockInput[]; stocks: ProductStockInput[];
} }
@ -35,18 +46,25 @@ export interface UseProductVariantCreateFormOpts {
currentChannels: ChannelPriceData[]; currentChannels: ChannelPriceData[];
} }
interface ProductVariantCreateHandlers
extends Record<
| "changeStock"
| "selectAttribute"
| "selectAttributeMultiple"
| "changeChannels",
FormsetChange
>,
Record<"selectAttributeFile", FormsetChange<File>>,
Record<"addStock" | "deleteStock", (id: string) => void> {
changeMetadata: FormChange;
}
export interface UseProductVariantCreateFormResult { export interface UseProductVariantCreateFormResult {
change: FormChange; change: FormChange;
data: ProductVariantCreateData; data: ProductVariantCreateData;
disabled: boolean; disabled: boolean;
// TODO: type FormsetChange // TODO: type FormsetChange
handlers: Record< handlers: ProductVariantCreateHandlers;
"changeStock" | "selectAttribute" | "changeChannels",
FormsetChange
> &
Record<"addStock" | "deleteStock", (id: string) => void> & {
changeMetadata: FormChange;
};
hasChanged: boolean; hasChanged: boolean;
submit: () => void; submit: () => void;
} }
@ -79,6 +97,7 @@ function useProductVariantCreateForm(
const form = useForm(initial); const form = useForm(initial);
const attributes = useFormset(attributeInput); const attributes = useFormset(attributeInput);
const attributesWithNewFileValue = useFormset<null, File>([]);
const stocks = useFormset<null, string>([]); const stocks = useFormset<null, string>([]);
const channels = useFormset(channelsInput); const channels = useFormset(channelsInput);
const { const {
@ -90,10 +109,22 @@ function useProductVariantCreateForm(
triggerChange(); triggerChange();
}; };
const changeMetadata = makeMetadataChangeHandler(handleChange); const changeMetadata = makeMetadataChangeHandler(handleChange);
const handleAttributeChange: FormsetChange = (id, value) => { const handleAttributeChange = createAttributeChangeHandler(
attributes.change(id, value); attributes.change,
triggerChange(); triggerChange
}; );
const handleAttributeMultiChange = createAttributeMultiChangeHandler(
attributes.change,
attributes.data,
triggerChange
);
const handleAttributeFileChange = createAttributeFileChangeHandler(
attributes.change,
attributesWithNewFileValue.data,
attributesWithNewFileValue.add,
attributesWithNewFileValue.change,
triggerChange
);
const handleStockAdd = (id: string) => { const handleStockAdd = (id: string) => {
triggerChange(); triggerChange();
stocks.add({ stocks.add({
@ -124,7 +155,11 @@ function useProductVariantCreateForm(
const data: ProductVariantCreateData = { const data: ProductVariantCreateData = {
...form.data, ...form.data,
attributes: attributes.data, attributes: getAttributesDisplayData(
attributes.data,
attributesWithNewFileValue.data
),
attributesWithNewFileValue: attributesWithNewFileValue.data,
channelListings: channels.data, channelListings: channels.data,
stocks: stocks.data stocks: stocks.data
}; };
@ -141,7 +176,9 @@ function useProductVariantCreateForm(
changeMetadata, changeMetadata,
changeStock: handleStockChange, changeStock: handleStockChange,
deleteStock: handleStockDelete, deleteStock: handleStockDelete,
selectAttribute: handleAttributeChange selectAttribute: handleAttributeChange,
selectAttributeFile: handleAttributeFileChange,
selectAttributeMultiple: handleAttributeMultiChange
}, },
hasChanged: changed, hasChanged: changed,
submit submit

View file

@ -1,9 +1,14 @@
import { ChannelPriceData } from "@saleor/channels/utils"; import { ChannelPriceData } from "@saleor/channels/utils";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import Attributes, {
AttributeInput,
VariantAttributeScope
} from "@saleor/components/Attributes";
import CardSpacer from "@saleor/components/CardSpacer"; import CardSpacer from "@saleor/components/CardSpacer";
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import Grid from "@saleor/components/Grid"; import Grid from "@saleor/components/Grid";
import { MetadataFormData } from "@saleor/components/Metadata";
import Metadata from "@saleor/components/Metadata/Metadata"; import Metadata from "@saleor/components/Metadata/Metadata";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SaveButtonBar from "@saleor/components/SaveButtonBar";
@ -14,11 +19,11 @@ import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment";
import { VariantUpdate_productVariantUpdate_errors } from "@saleor/products/types/VariantUpdate"; import { VariantUpdate_productVariantUpdate_errors } from "@saleor/products/types/VariantUpdate";
import { ReorderAction } from "@saleor/types"; import { ReorderAction } from "@saleor/types";
import React from "react"; import React from "react";
import { defineMessages, useIntl } from "react-intl";
import { maybe } from "../../../misc"; import { maybe } from "../../../misc";
import ProductShipping from "../ProductShipping/ProductShipping"; import ProductShipping from "../ProductShipping/ProductShipping";
import ProductStocks from "../ProductStocks"; import ProductStocks, { ProductStockInput } from "../ProductStocks";
import ProductVariantAttributes from "../ProductVariantAttributes";
import ProductVariantImages from "../ProductVariantImages"; import ProductVariantImages from "../ProductVariantImages";
import ProductVariantImageSelectDialog from "../ProductVariantImageSelectDialog"; import ProductVariantImageSelectDialog from "../ProductVariantImageSelectDialog";
import ProductVariantNavigation from "../ProductVariantNavigation"; import ProductVariantNavigation from "../ProductVariantNavigation";
@ -28,6 +33,33 @@ import ProductVariantUpdateForm, {
ProductVariantUpdateSubmitData ProductVariantUpdateSubmitData
} from "./form"; } from "./form";
const messages = defineMessages({
nonSelectionAttributes: {
defaultMessage: "Variant Attributes",
description: "attributes, section header"
},
selectionAttributesHeader: {
defaultMessage: "Variant Selection Attributes",
description: "attributes, section header"
}
});
export interface ProductVariantPageFormData extends MetadataFormData {
costPrice: string;
price: string;
sku: string;
trackInventory: boolean;
weight: string;
}
export interface ProductVariantPageSubmitData
extends ProductVariantPageFormData {
attributes: AttributeInput[];
addStocks: ProductStockInput[];
updateStocks: ProductStockInput[];
removeStocks: string[];
}
interface ProductVariantPageProps { interface ProductVariantPageProps {
defaultVariantId?: string; defaultVariantId?: string;
defaultWeightUnit: string; defaultWeightUnit: string;
@ -75,6 +107,8 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
onSetDefaultVariant, onSetDefaultVariant,
onWarehouseConfigure onWarehouseConfigure
}) => { }) => {
const intl = useIntl();
const [isModalOpened, setModalStatus] = React.useState(false); const [isModalOpened, setModalStatus] = React.useState(false);
const toggleModal = () => setModalStatus(!isModalOpened); const toggleModal = () => setModalStatus(!isModalOpened);
@ -131,11 +165,36 @@ const ProductVariantPage: React.FC<ProductVariantPageProps> = ({
/> />
</div> </div>
<div> <div>
<ProductVariantAttributes <Attributes
attributes={data.attributes} title={intl.formatMessage(messages.nonSelectionAttributes)}
attributes={data.attributes.filter(
attribute =>
attribute.data.variantAttributeScope ===
VariantAttributeScope.NOT_VARIANT_SELECTION
)}
loading={loading}
disabled={loading} disabled={loading}
errors={errors} errors={errors}
onChange={handlers.selectAttribute} onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple}
onFileChange={handlers.selectAttributeFile}
/>
<CardSpacer />
<Attributes
title={intl.formatMessage(
messages.selectionAttributesHeader
)}
attributes={data.attributes.filter(
attribute =>
attribute.data.variantAttributeScope ===
VariantAttributeScope.VARIANT_SELECTION
)}
loading={loading}
disabled={loading}
errors={errors}
onChange={handlers.selectAttribute}
onMultiChange={handlers.selectAttributeMultiple}
onFileChange={handlers.selectAttributeFile}
/> />
<CardSpacer /> <CardSpacer />
<ProductVariantImages <ProductVariantImages

View file

@ -1,4 +1,5 @@
import { ChannelPriceData, IChannelPriceArgs } from "@saleor/channels/utils"; import { ChannelPriceData, IChannelPriceArgs } from "@saleor/channels/utils";
import { AttributeInput } from "@saleor/components/Attributes";
import { MetadataFormData } from "@saleor/components/Metadata"; import { MetadataFormData } from "@saleor/components/Metadata";
import { ProductVariant } from "@saleor/fragments/types/ProductVariant"; import { ProductVariant } from "@saleor/fragments/types/ProductVariant";
import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm"; import useForm, { FormChange, SubmitPromise } from "@saleor/hooks/useForm";
@ -8,9 +9,17 @@ import useFormset, {
} from "@saleor/hooks/useFormset"; } from "@saleor/hooks/useFormset";
import { import {
getAttributeInputFromVariant, getAttributeInputFromVariant,
getAttributesDisplayData,
getStockInputFromVariant getStockInputFromVariant
} from "@saleor/products/utils/data"; } from "@saleor/products/utils/data";
import { getChannelsInput } from "@saleor/products/utils/handlers"; import {
createAttributeFileChangeHandler,
getChannelsInput
} from "@saleor/products/utils/handlers";
import {
createAttributeChangeHandler,
createAttributeMultiChangeHandler
} from "@saleor/products/utils/handlers";
import { import {
validateCostPrice, validateCostPrice,
validatePrice validatePrice
@ -20,11 +29,10 @@ import { mapMetadataItemToInput } from "@saleor/utils/maps";
import getMetadata from "@saleor/utils/metadata/getMetadata"; import getMetadata from "@saleor/utils/metadata/getMetadata";
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger"; import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
import { diff } from "fast-array-diff"; import { diff } from "fast-array-diff";
import React from "react"; import React, { useEffect } from "react";
import handleFormSubmit from "../../../utils/handlers/handleFormSubmit"; import handleFormSubmit from "../../../utils/handlers/handleFormSubmit";
import { ProductStockInput } from "../ProductStocks"; import { ProductStockInput } from "../ProductStocks";
import { VariantAttributeInputData } from "../ProductVariantAttributes";
export interface ProductVariantUpdateFormData extends MetadataFormData { export interface ProductVariantUpdateFormData extends MetadataFormData {
sku: string; sku: string;
@ -32,13 +40,14 @@ export interface ProductVariantUpdateFormData extends MetadataFormData {
weight: string; weight: string;
} }
export interface ProductVariantUpdateData extends ProductVariantUpdateFormData { export interface ProductVariantUpdateData extends ProductVariantUpdateFormData {
attributes: FormsetData<VariantAttributeInputData, string>;
channelListings: FormsetData<ChannelPriceData, IChannelPriceArgs>; channelListings: FormsetData<ChannelPriceData, IChannelPriceArgs>;
attributes: AttributeInput[];
stocks: ProductStockInput[]; stocks: ProductStockInput[];
} }
export interface ProductVariantUpdateSubmitData export interface ProductVariantUpdateSubmitData
extends ProductVariantUpdateFormData { extends ProductVariantUpdateFormData {
attributes: FormsetData<VariantAttributeInputData, string>; attributes: AttributeInput[];
attributesWithNewFileValue: FormsetData<null, File>;
addStocks: ProductStockInput[]; addStocks: ProductStockInput[];
channelListings: FormsetData<ChannelPriceData, IChannelPriceArgs>; channelListings: FormsetData<ChannelPriceData, IChannelPriceArgs>;
updateStocks: ProductStockInput[]; updateStocks: ProductStockInput[];
@ -50,17 +59,24 @@ export interface UseProductVariantUpdateFormOpts {
currentChannels: ChannelPriceData[]; currentChannels: ChannelPriceData[];
} }
interface ProductVariantUpdateHandlers
extends Record<
| "changeStock"
| "selectAttribute"
| "selectAttributeMultiple"
| "changeChannels",
FormsetChange
>,
Record<"selectAttributeFile", FormsetChange<File>>,
Record<"addStock" | "deleteStock", (id: string) => void> {
changeMetadata: FormChange;
}
export interface UseProductVariantUpdateFormResult { export interface UseProductVariantUpdateFormResult {
change: FormChange; change: FormChange;
data: ProductVariantUpdateData; data: ProductVariantUpdateData;
disabled: boolean; disabled: boolean;
handlers: Record< handlers: ProductVariantUpdateHandlers;
"changeStock" | "selectAttribute" | "changeChannels",
FormsetChange
> &
Record<"addStock" | "deleteStock", (id: string) => void> & {
changeMetadata: FormChange;
};
hasChanged: boolean; hasChanged: boolean;
submit: () => void; submit: () => void;
} }
@ -94,6 +110,7 @@ function useProductVariantUpdateForm(
const form = useForm(initial); const form = useForm(initial);
const attributes = useFormset(attributeInput); const attributes = useFormset(attributeInput);
const attributesWithNewFileValue = useFormset<null, File>([]);
const stocks = useFormset(stockInput); const stocks = useFormset(stockInput);
const channels = useFormset(channelsInput); const channels = useFormset(channelsInput);
const { const {
@ -107,10 +124,22 @@ function useProductVariantUpdateForm(
triggerChange(); triggerChange();
}; };
const changeMetadata = makeMetadataChangeHandler(handleChange); const changeMetadata = makeMetadataChangeHandler(handleChange);
const handleAttributeChange: FormsetChange = (id, value) => { const handleAttributeChange = createAttributeChangeHandler(
attributes.change(id, value); attributes.change,
triggerChange(); triggerChange
}; );
const handleAttributeMultiChange = createAttributeMultiChangeHandler(
attributes.change,
attributes.data,
triggerChange
);
const handleAttributeFileChange = createAttributeFileChangeHandler(
attributes.change,
attributesWithNewFileValue.data,
attributesWithNewFileValue.add,
attributesWithNewFileValue.change,
triggerChange
);
const handleStockAdd = (id: string) => { const handleStockAdd = (id: string) => {
triggerChange(); triggerChange();
stocks.add({ stocks.add({
@ -137,6 +166,10 @@ function useProductVariantUpdateForm(
triggerChange(); triggerChange();
}; };
useEffect(() => {
attributesWithNewFileValue.set([]);
}, [variant]);
const dataStocks = stocks.data.map(stock => stock.id); const dataStocks = stocks.data.map(stock => stock.id);
const variantStocks = variant?.stocks.map(stock => stock.warehouse.id) || []; const variantStocks = variant?.stocks.map(stock => stock.warehouse.id) || [];
const stockDiff = diff(variantStocks, dataStocks); const stockDiff = diff(variantStocks, dataStocks);
@ -155,7 +188,10 @@ function useProductVariantUpdateForm(
); );
const data: ProductVariantUpdateData = { const data: ProductVariantUpdateData = {
...form.data, ...form.data,
attributes: attributes.data, attributes: getAttributesDisplayData(
attributes.data,
attributesWithNewFileValue.data
),
channelListings: channels.data, channelListings: channels.data,
stocks: stocks.data stocks: stocks.data
}; };
@ -164,6 +200,7 @@ function useProductVariantUpdateForm(
...getMetadata(form.data, isMetadataModified, isPrivateMetadataModified), ...getMetadata(form.data, isMetadataModified, isPrivateMetadataModified),
addStocks, addStocks,
attributes: attributes.data, attributes: attributes.data,
attributesWithNewFileValue: attributesWithNewFileValue.data,
channelListings: channels.data, channelListings: channels.data,
removeStocks: stockDiff.removed, removeStocks: stockDiff.removed,
updateStocks updateStocks
@ -181,7 +218,9 @@ function useProductVariantUpdateForm(
changeMetadata, changeMetadata,
changeStock: handleStockChange, changeStock: handleStockChange,
deleteStock: handleStockDelete, deleteStock: handleStockDelete,
selectAttribute: handleAttributeChange selectAttribute: handleAttributeChange,
selectAttributeFile: handleAttributeFileChange,
selectAttributeMultiple: handleAttributeMultiChange
}, },
hasChanged: changed, hasChanged: changed,
submit submit

View file

@ -30,12 +30,14 @@ export const product: (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav47282", id: "ptav47282",
name: "portals", name: "portals",
slug: "portals" slug: "portals"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav17253", id: "ptav17253",
name: "Baht", name: "Baht",
slug: "Baht" slug: "Baht"
@ -45,6 +47,7 @@ export const product: (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav47282", id: "ptav47282",
name: "portals", name: "portals",
slug: "portals" slug: "portals"
@ -63,24 +66,28 @@ export const product: (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav31282", id: "ptav31282",
name: "payment", name: "payment",
slug: "payment" slug: "payment"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav14907", id: "ptav14907",
name: "Auto Loan Account", name: "Auto Loan Account",
slug: "Auto-Loan-Account" slug: "Auto-Loan-Account"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav27366", id: "ptav27366",
name: "Garden", name: "Garden",
slug: "Garden" slug: "Garden"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav11873", id: "ptav11873",
name: "override", name: "override",
slug: "override" slug: "override"
@ -90,6 +97,7 @@ export const product: (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptav14907", id: "ptav14907",
name: "Auto Loan Account", name: "Auto Loan Account",
slug: "Auto-Loan-Account" slug: "Auto-Loan-Account"
@ -243,6 +251,55 @@ export const product: (
hasVariants: true, hasVariants: true,
id: "pt76406", id: "pt76406",
name: "Versatile", name: "Versatile",
nonSelectionVariantAttributes: [
{
__typename: "Attribute",
id: "isdugfhud",
inputType: AttributeInputTypeEnum.FILE,
name: "Attachment",
slug: "attachment",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "gdghdgdhkkdae",
name: "File First Value",
slug: "file-first-value"
}
]
}
],
selectionVariantAttributes: [
{
__typename: "Attribute",
id: "pta18161",
inputType: AttributeInputTypeEnum.DROPDOWN,
name: "Color",
slug: "color",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
file: null,
id: "ptvav47282",
name: "Black",
slug: "black"
},
{
__typename: "AttributeValue",
file: null,
id: "ptvav17253",
name: "White",
slug: "white"
}
]
}
],
taxType: { taxType: {
__typename: "TaxType", __typename: "TaxType",
description: "standard", description: "standard",
@ -251,25 +308,46 @@ export const product: (
variantAttributes: [ variantAttributes: [
{ {
__typename: "Attribute", __typename: "Attribute",
id: "pta18161", id: "isdugfhud",
name: "Color", inputType: AttributeInputTypeEnum.FILE,
slug: "color", name: "Attachment",
sortOrder: 0, slug: "attachment",
valueRequired: true, valueRequired: true,
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "gdghdgdhkkdae",
name: "File First Value",
slug: "file-first-value"
}
]
},
{
__typename: "Attribute",
id: "pta18161",
inputType: AttributeInputTypeEnum.DROPDOWN,
name: "Color",
slug: "color",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
file: null,
id: "ptvav47282", id: "ptvav47282",
name: "Black", name: "Black",
slug: "black", slug: "black"
sortOrder: 0
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "ptvav17253", id: "ptvav17253",
name: "White", name: "White",
slug: "white", slug: "white"
sortOrder: 1
} }
] ]
} }
@ -713,8 +791,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6MQ==", id: "QXR0cmlidXRlVmFsdWU6MQ==",
name: "Pineapple" name: "Pineapple",
slug: "pineapple"
} }
] ]
} }
@ -818,8 +898,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6Mg==", id: "QXR0cmlidXRlVmFsdWU6Mg==",
name: "Coconut" name: "Coconut",
slug: "coconut"
} }
] ]
} }
@ -923,8 +1005,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6Mw==", id: "QXR0cmlidXRlVmFsdWU6Mw==",
name: "Apple" name: "Apple",
slug: "apple"
} }
] ]
} }
@ -1029,8 +1113,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6NDk=", id: "QXR0cmlidXRlVmFsdWU6NDk=",
name: "Orange" name: "Orange",
slug: "orange"
} }
] ]
} }
@ -1134,8 +1220,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6NTA=", id: "QXR0cmlidXRlVmFsdWU6NTA=",
name: "Banana" name: "Banana",
slug: "banana"
} }
] ]
} }
@ -1239,8 +1327,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6NTE=", id: "QXR0cmlidXRlVmFsdWU6NTE=",
name: "Bean" name: "Bean",
slug: "bean"
} }
] ]
} }
@ -1344,8 +1434,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6NTI=", id: "QXR0cmlidXRlVmFsdWU6NTI=",
name: "Carrot" name: "Carrot",
slug: "carrot"
} }
] ]
} }
@ -1449,8 +1541,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6NTM=", id: "QXR0cmlidXRlVmFsdWU6NTM=",
name: "Sprouty" name: "Sprouty",
slug: "sprouty"
} }
] ]
} }
@ -1554,8 +1648,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -1659,8 +1755,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -1764,8 +1862,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -1869,8 +1969,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -1974,8 +2076,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -2079,8 +2183,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -2184,8 +2290,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -2289,8 +2397,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6ODI=", id: "QXR0cmlidXRlVmFsdWU6ODI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -2394,8 +2504,10 @@ export const products = (
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "QXR0cmlidXRlVmFsdWU6NzI=", id: "QXR0cmlidXRlVmFsdWU6NzI=",
name: "Cotton" name: "Cotton",
slug: "cotton"
} }
] ]
} }
@ -2491,84 +2603,6 @@ export const products = (
export const variant = (placeholderImage: string): ProductVariant => ({ export const variant = (placeholderImage: string): ProductVariant => ({
__typename: "ProductVariant", __typename: "ProductVariant",
attributes: [
{
__typename: "SelectedAttribute",
attribute: {
__typename: "Attribute" as "Attribute",
id: "pta18161",
name: "Borders",
slug: "Borders",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
id: "ptav47282",
name: "portals",
slug: "portals"
},
{
__typename: "AttributeValue",
id: "ptav17253",
name: "Baht",
slug: "Baht"
}
]
},
values: [
{
__typename: "AttributeValue",
id: "ptav47282",
name: "portals",
slug: "portals"
}
]
},
{
__typename: "SelectedAttribute",
attribute: {
__typename: "Attribute" as "Attribute",
id: "pta22785",
name: "Legacy",
slug: "Legacy",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
id: "ptav31282",
name: "payment",
slug: "payment"
},
{
__typename: "AttributeValue",
id: "ptav14907",
name: "Auto Loan Account",
slug: "Auto-Loan-Account"
},
{
__typename: "AttributeValue",
id: "ptav27366",
name: "Garden",
slug: "Garden"
},
{
__typename: "AttributeValue",
id: "ptav11873",
name: "override",
slug: "override"
}
]
},
values: [
{
__typename: "AttributeValue",
id: "ptav14907",
name: "Auto Loan Account",
slug: "Auto-Loan-Account"
}
]
}
],
channelListings: [ channelListings: [
{ {
__typename: "ProductVariantChannelListing", __typename: "ProductVariantChannelListing",
@ -2640,6 +2674,45 @@ export const variant = (placeholderImage: string): ProductVariant => ({
} }
], ],
name: "Extended Hard", name: "Extended Hard",
nonSelectionAttributes: [
{
__typename: "SelectedAttribute",
attribute: {
__typename: "Attribute",
id: "nfnyffcf8eyfm",
inputType: AttributeInputTypeEnum.FILE,
name: "Attachment",
slug: "attachment",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "gdghdgdhkkdae",
name: "File First Value",
slug: "file-first-value"
}
]
},
values: [
{
__typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "gdghdgdhkkdae",
name: "File First Value",
slug: "file-first-value"
}
]
}
],
privateMetadata: [], privateMetadata: [],
product: { product: {
__typename: "Product" as "Product", __typename: "Product" as "Product",
@ -2834,6 +2907,94 @@ export const variant = (placeholderImage: string): ProductVariant => ({
} }
] ]
}, },
selectionAttributes: [
{
__typename: "SelectedAttribute",
attribute: {
__typename: "Attribute" as "Attribute",
id: "pta18161",
inputType: AttributeInputTypeEnum.DROPDOWN,
name: "Borders",
slug: "Borders",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
file: null,
id: "ptav47282",
name: "portals",
slug: "portals"
},
{
__typename: "AttributeValue",
file: null,
id: "ptav17253",
name: "Baht",
slug: "Baht"
}
]
},
values: [
{
__typename: "AttributeValue",
file: null,
id: "ptav47282",
name: "portals",
slug: "portals"
}
]
},
{
__typename: "SelectedAttribute",
attribute: {
__typename: "Attribute" as "Attribute",
id: "pta22785",
inputType: AttributeInputTypeEnum.DROPDOWN,
name: "Legacy",
slug: "Legacy",
valueRequired: true,
values: [
{
__typename: "AttributeValue",
file: null,
id: "ptav31282",
name: "payment",
slug: "payment"
},
{
__typename: "AttributeValue",
file: null,
id: "ptav14907",
name: "Auto Loan Account",
slug: "Auto-Loan-Account"
},
{
__typename: "AttributeValue",
file: null,
id: "ptav27366",
name: "Garden",
slug: "Garden"
},
{
__typename: "AttributeValue",
file: null,
id: "ptav11873",
name: "override",
slug: "override"
}
]
},
values: [
{
__typename: "AttributeValue",
file: null,
id: "ptav14907",
name: "Auto Loan Account",
slug: "Auto-Loan-Account"
}
]
}
],
sku: "1230959124123", sku: "1230959124123",
stocks: [ stocks: [
{ {

View file

@ -1,9 +1,11 @@
import { attributeValueFragment } from "@saleor/fragments/attributes";
import { pageInfoFragment } from "@saleor/fragments/pageInfo"; import { pageInfoFragment } from "@saleor/fragments/pageInfo";
import { import {
fragmentVariant, fragmentVariant,
productFragment, productFragment,
productFragmentDetails, productFragmentDetails,
productVariantAttributesFragment productVariantAttributesFragment,
variantAttributeFragment
} from "@saleor/fragments/products"; } from "@saleor/fragments/products";
import { taxTypeFragment } from "@saleor/fragments/taxes"; import { taxTypeFragment } from "@saleor/fragments/taxes";
import { warehouseFragment } from "@saleor/fragments/warehouses"; import { warehouseFragment } from "@saleor/fragments/warehouses";
@ -94,6 +96,7 @@ export const useInitialProductFilterDataQuery = makeQuery<
const productListQuery = gql` const productListQuery = gql`
${productFragment} ${productFragment}
${attributeValueFragment}
query ProductList( query ProductList(
$first: Int $first: Int
$after: String $after: String
@ -118,8 +121,7 @@ const productListQuery = gql`
id id
} }
values { values {
id ...AttributeValueFragment
name
} }
} }
} }
@ -185,6 +187,7 @@ export const useProductVariantQuery = makeQuery<
>(productVariantQuery); >(productVariantQuery);
const productVariantCreateQuery = gql` const productVariantCreateQuery = gql`
${variantAttributeFragment}
query ProductVariantCreateData($id: ID!) { query ProductVariantCreateData($id: ID!) {
product(id: $id) { product(id: $id) {
id id
@ -203,16 +206,15 @@ const productVariantCreateQuery = gql`
name name
productType { productType {
id id
variantAttributes { selectionVariantAttributes: variantAttributes(
id variantSelection: VARIANT_SELECTION
slug ) {
name ...VariantAttributeFragment
valueRequired }
values { nonSelectionVariantAttributes: variantAttributes(
id variantSelection: NOT_VARIANT_SELECTION
name ) {
slug ...VariantAttributeFragment
}
} }
} }
thumbnail { thumbnail {

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// GraphQL query operation: CreateMultipleVariantsData // GraphQL query operation: CreateMultipleVariantsData
// ==================================================== // ====================================================
export interface CreateMultipleVariantsData_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface CreateMultipleVariantsData_product_attributes_attribute_values { export interface CreateMultipleVariantsData_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: CreateMultipleVariantsData_product_attributes_attribute_values_file | null;
} }
export interface CreateMultipleVariantsData_product_attributes_attribute { export interface CreateMultipleVariantsData_product_attributes_attribute {
@ -25,11 +32,18 @@ export interface CreateMultipleVariantsData_product_attributes_attribute {
values: (CreateMultipleVariantsData_product_attributes_attribute_values | null)[] | null; values: (CreateMultipleVariantsData_product_attributes_attribute_values | null)[] | null;
} }
export interface CreateMultipleVariantsData_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface CreateMultipleVariantsData_product_attributes_values { export interface CreateMultipleVariantsData_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: CreateMultipleVariantsData_product_attributes_values_file | null;
} }
export interface CreateMultipleVariantsData_product_attributes { export interface CreateMultipleVariantsData_product_attributes {
@ -38,11 +52,18 @@ export interface CreateMultipleVariantsData_product_attributes {
values: (CreateMultipleVariantsData_product_attributes_values | null)[]; values: (CreateMultipleVariantsData_product_attributes_values | null)[];
} }
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface CreateMultipleVariantsData_product_productType_variantAttributes_values { export interface CreateMultipleVariantsData_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: CreateMultipleVariantsData_product_productType_variantAttributes_values_file | null;
} }
export interface CreateMultipleVariantsData_product_productType_variantAttributes { export interface CreateMultipleVariantsData_product_productType_variantAttributes {

View file

@ -8,11 +8,18 @@ import { ProductChannelListingUpdateInput, AttributeInputTypeEnum, WeightUnitsEn
// GraphQL mutation operation: ProductChannelListingUpdate // GraphQL mutation operation: ProductChannelListingUpdate
// ==================================================== // ====================================================
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute_values { export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute_values_file | null;
} }
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute { export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute {
@ -25,11 +32,18 @@ export interface ProductChannelListingUpdate_productChannelListingUpdate_product
values: (ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute_values | null)[] | null; values: (ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_values { export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_values_file | null;
} }
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes { export interface ProductChannelListingUpdate_productChannelListingUpdate_product_attributes {
@ -38,11 +52,18 @@ export interface ProductChannelListingUpdate_productChannelListingUpdate_product
values: (ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_values | null)[]; values: (ProductChannelListingUpdate_productChannelListingUpdate_product_attributes_values | null)[];
} }
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_productType_variantAttributes_values { export interface ProductChannelListingUpdate_productChannelListingUpdate_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductChannelListingUpdate_productChannelListingUpdate_product_productType_variantAttributes_values_file | null;
} }
export interface ProductChannelListingUpdate_productChannelListingUpdate_product_productType_variantAttributes { export interface ProductChannelListingUpdate_productChannelListingUpdate_product_productType_variantAttributes {

View file

@ -15,11 +15,18 @@ export interface ProductCreate_productCreate_errors {
attributes: string[] | null; attributes: string[] | null;
} }
export interface ProductCreate_productCreate_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductCreate_productCreate_product_attributes_attribute_values { export interface ProductCreate_productCreate_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductCreate_productCreate_product_attributes_attribute_values_file | null;
} }
export interface ProductCreate_productCreate_product_attributes_attribute { export interface ProductCreate_productCreate_product_attributes_attribute {
@ -32,11 +39,18 @@ export interface ProductCreate_productCreate_product_attributes_attribute {
values: (ProductCreate_productCreate_product_attributes_attribute_values | null)[] | null; values: (ProductCreate_productCreate_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductCreate_productCreate_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductCreate_productCreate_product_attributes_values { export interface ProductCreate_productCreate_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductCreate_productCreate_product_attributes_values_file | null;
} }
export interface ProductCreate_productCreate_product_attributes { export interface ProductCreate_productCreate_product_attributes {
@ -45,11 +59,18 @@ export interface ProductCreate_productCreate_product_attributes {
values: (ProductCreate_productCreate_product_attributes_values | null)[]; values: (ProductCreate_productCreate_product_attributes_values | null)[];
} }
export interface ProductCreate_productCreate_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductCreate_productCreate_product_productType_variantAttributes_values { export interface ProductCreate_productCreate_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductCreate_productCreate_product_productType_variantAttributes_values_file | null;
} }
export interface ProductCreate_productCreate_product_productType_variantAttributes { export interface ProductCreate_productCreate_product_productType_variantAttributes {

View file

@ -8,11 +8,18 @@ import { AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTyp
// GraphQL query operation: ProductDetails // GraphQL query operation: ProductDetails
// ==================================================== // ====================================================
export interface ProductDetails_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductDetails_product_attributes_attribute_values { export interface ProductDetails_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductDetails_product_attributes_attribute_values_file | null;
} }
export interface ProductDetails_product_attributes_attribute { export interface ProductDetails_product_attributes_attribute {
@ -25,11 +32,18 @@ export interface ProductDetails_product_attributes_attribute {
values: (ProductDetails_product_attributes_attribute_values | null)[] | null; values: (ProductDetails_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductDetails_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductDetails_product_attributes_values { export interface ProductDetails_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductDetails_product_attributes_values_file | null;
} }
export interface ProductDetails_product_attributes { export interface ProductDetails_product_attributes {
@ -38,11 +52,18 @@ export interface ProductDetails_product_attributes {
values: (ProductDetails_product_attributes_values | null)[]; values: (ProductDetails_product_attributes_values | null)[];
} }
export interface ProductDetails_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductDetails_product_productType_variantAttributes_values { export interface ProductDetails_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductDetails_product_productType_variantAttributes_values_file | null;
} }
export interface ProductDetails_product_productType_variantAttributes { export interface ProductDetails_product_productType_variantAttributes {

View file

@ -14,11 +14,18 @@ export interface ProductImageCreate_productImageCreate_errors {
field: string | null; field: string | null;
} }
export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values { export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductImageCreate_productImageCreate_product_attributes_attribute_values_file | null;
} }
export interface ProductImageCreate_productImageCreate_product_attributes_attribute { export interface ProductImageCreate_productImageCreate_product_attributes_attribute {
@ -31,11 +38,18 @@ export interface ProductImageCreate_productImageCreate_product_attributes_attrib
values: (ProductImageCreate_productImageCreate_product_attributes_attribute_values | null)[] | null; values: (ProductImageCreate_productImageCreate_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductImageCreate_productImageCreate_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductImageCreate_productImageCreate_product_attributes_values { export interface ProductImageCreate_productImageCreate_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductImageCreate_productImageCreate_product_attributes_values_file | null;
} }
export interface ProductImageCreate_productImageCreate_product_attributes { export interface ProductImageCreate_productImageCreate_product_attributes {
@ -44,11 +58,18 @@ export interface ProductImageCreate_productImageCreate_product_attributes {
values: (ProductImageCreate_productImageCreate_product_attributes_values | null)[]; values: (ProductImageCreate_productImageCreate_product_attributes_values | null)[];
} }
export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes_values { export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductImageCreate_productImageCreate_product_productType_variantAttributes_values_file | null;
} }
export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes { export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes {

View file

@ -14,11 +14,18 @@ export interface ProductImageUpdate_productImageUpdate_errors {
field: string | null; field: string | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values { export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductImageUpdate_productImageUpdate_product_attributes_attribute_values_file | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute { export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute {
@ -31,11 +38,18 @@ export interface ProductImageUpdate_productImageUpdate_product_attributes_attrib
values: (ProductImageUpdate_productImageUpdate_product_attributes_attribute_values | null)[] | null; values: (ProductImageUpdate_productImageUpdate_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductImageUpdate_productImageUpdate_product_attributes_values { export interface ProductImageUpdate_productImageUpdate_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductImageUpdate_productImageUpdate_product_attributes_values_file | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_attributes { export interface ProductImageUpdate_productImageUpdate_product_attributes {
@ -44,11 +58,18 @@ export interface ProductImageUpdate_productImageUpdate_product_attributes {
values: (ProductImageUpdate_productImageUpdate_product_attributes_values | null)[]; values: (ProductImageUpdate_productImageUpdate_product_attributes_values | null)[];
} }
export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values { export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values_file | null;
} }
export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes { export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes {

View file

@ -76,10 +76,18 @@ export interface ProductList_products_edges_node_attributes_attribute {
id: string; id: string;
} }
export interface ProductList_products_edges_node_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductList_products_edges_node_attributes_values { export interface ProductList_products_edges_node_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null;
file: ProductList_products_edges_node_attributes_values_file | null;
} }
export interface ProductList_products_edges_node_attributes { export interface ProductList_products_edges_node_attributes {

View file

@ -15,11 +15,18 @@ export interface ProductUpdate_productUpdate_errors {
attributes: string[] | null; attributes: string[] | null;
} }
export interface ProductUpdate_productUpdate_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductUpdate_productUpdate_product_attributes_attribute_values { export interface ProductUpdate_productUpdate_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductUpdate_productUpdate_product_attributes_attribute_values_file | null;
} }
export interface ProductUpdate_productUpdate_product_attributes_attribute { export interface ProductUpdate_productUpdate_product_attributes_attribute {
@ -32,11 +39,18 @@ export interface ProductUpdate_productUpdate_product_attributes_attribute {
values: (ProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; values: (ProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductUpdate_productUpdate_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductUpdate_productUpdate_product_attributes_values { export interface ProductUpdate_productUpdate_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductUpdate_productUpdate_product_attributes_values_file | null;
} }
export interface ProductUpdate_productUpdate_product_attributes { export interface ProductUpdate_productUpdate_product_attributes {
@ -45,11 +59,18 @@ export interface ProductUpdate_productUpdate_product_attributes {
values: (ProductUpdate_productUpdate_product_attributes_values | null)[]; values: (ProductUpdate_productUpdate_product_attributes_values | null)[];
} }
export interface ProductUpdate_productUpdate_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductUpdate_productUpdate_product_productType_variantAttributes_values { export interface ProductUpdate_productUpdate_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductUpdate_productUpdate_product_productType_variantAttributes_values_file | null;
} }
export interface ProductUpdate_productUpdate_product_productType_variantAttributes { export interface ProductUpdate_productUpdate_product_productType_variantAttributes {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { ProductVariantChannelListingAddInput, WeightUnitsEnum, ProductErrorCode } from "./../../types/globalTypes"; import { ProductVariantChannelListingAddInput, AttributeInputTypeEnum, WeightUnitsEnum, ProductErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: ProductVariantChannelListingUpdate // GraphQL mutation operation: ProductVariantChannelListingUpdate
@ -20,33 +20,92 @@ export interface ProductVariantChannelListingUpdate_productVariantChannelListing
value: string; value: string;
} }
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes_attribute_values { export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_attribute_values_file | null;
} }
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes_attribute { export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes_attribute_values | null)[] | null; values: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes_values { export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_values_file | null;
} }
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes { export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes_attribute; attribute: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_attribute;
values: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes_values | null)[]; values: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes_values | null)[];
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_attribute_values_file | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_values_file | null;
}
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_attribute;
values: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes_values | null)[];
} }
export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_images { export interface ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_images {
@ -195,7 +254,8 @@ export interface ProductVariantChannelListingUpdate_productVariantChannelListing
id: string; id: string;
metadata: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_metadata | null)[]; metadata: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_metadata | null)[];
privateMetadata: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_privateMetadata | null)[]; privateMetadata: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_privateMetadata | null)[];
attributes: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_attributes[]; selectionAttributes: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_selectionAttributes[];
nonSelectionAttributes: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_nonSelectionAttributes[];
images: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_images | null)[] | null; images: (ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_images | null)[] | null;
name: string; name: string;
product: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_product; product: ProductVariantChannelListingUpdate_productVariantChannelListingUpdate_variant_product;

View file

@ -2,6 +2,8 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { AttributeInputTypeEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL query operation: ProductVariantCreateData // GraphQL query operation: ProductVariantCreateData
// ==================================================== // ====================================================
@ -25,26 +27,59 @@ export interface ProductVariantCreateData_product_channelListings {
channel: ProductVariantCreateData_product_channelListings_channel; channel: ProductVariantCreateData_product_channelListings_channel;
} }
export interface ProductVariantCreateData_product_productType_variantAttributes_values { export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantCreateData_product_productType_selectionVariantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantCreateData_product_productType_selectionVariantAttributes_values_file | null;
} }
export interface ProductVariantCreateData_product_productType_variantAttributes { export interface ProductVariantCreateData_product_productType_selectionVariantAttributes {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
slug: string | null;
name: string | null; name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (ProductVariantCreateData_product_productType_variantAttributes_values | null)[] | null; values: (ProductVariantCreateData_product_productType_selectionVariantAttributes_values | null)[] | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values_file | null;
}
export interface ProductVariantCreateData_product_productType_nonSelectionVariantAttributes {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (ProductVariantCreateData_product_productType_nonSelectionVariantAttributes_values | null)[] | null;
} }
export interface ProductVariantCreateData_product_productType { export interface ProductVariantCreateData_product_productType {
__typename: "ProductType"; __typename: "ProductType";
id: string; id: string;
variantAttributes: (ProductVariantCreateData_product_productType_variantAttributes | null)[] | null; selectionVariantAttributes: (ProductVariantCreateData_product_productType_selectionVariantAttributes | null)[] | null;
nonSelectionVariantAttributes: (ProductVariantCreateData_product_productType_nonSelectionVariantAttributes | null)[] | null;
} }
export interface ProductVariantCreateData_product_thumbnail { export interface ProductVariantCreateData_product_thumbnail {

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { WeightUnitsEnum } from "./../../types/globalTypes"; import { AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL query operation: ProductVariantDetails // GraphQL query operation: ProductVariantDetails
@ -20,33 +20,92 @@ export interface ProductVariantDetails_productVariant_privateMetadata {
value: string; value: string;
} }
export interface ProductVariantDetails_productVariant_attributes_attribute_values { export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantDetails_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface ProductVariantDetails_productVariant_attributes_attribute { export interface ProductVariantDetails_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (ProductVariantDetails_productVariant_attributes_attribute_values | null)[] | null; values: (ProductVariantDetails_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface ProductVariantDetails_productVariant_attributes_values { export interface ProductVariantDetails_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantDetails_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantDetails_productVariant_selectionAttributes_values_file | null;
} }
export interface ProductVariantDetails_productVariant_attributes { export interface ProductVariantDetails_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: ProductVariantDetails_productVariant_attributes_attribute; attribute: ProductVariantDetails_productVariant_selectionAttributes_attribute;
values: (ProductVariantDetails_productVariant_attributes_values | null)[]; values: (ProductVariantDetails_productVariant_selectionAttributes_values | null)[];
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (ProductVariantDetails_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: ProductVariantDetails_productVariant_nonSelectionAttributes_values_file | null;
}
export interface ProductVariantDetails_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: ProductVariantDetails_productVariant_nonSelectionAttributes_attribute;
values: (ProductVariantDetails_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface ProductVariantDetails_productVariant_images { export interface ProductVariantDetails_productVariant_images {
@ -195,7 +254,8 @@ export interface ProductVariantDetails_productVariant {
id: string; id: string;
metadata: (ProductVariantDetails_productVariant_metadata | null)[]; metadata: (ProductVariantDetails_productVariant_metadata | null)[];
privateMetadata: (ProductVariantDetails_productVariant_privateMetadata | null)[]; privateMetadata: (ProductVariantDetails_productVariant_privateMetadata | null)[];
attributes: ProductVariantDetails_productVariant_attributes[]; selectionAttributes: ProductVariantDetails_productVariant_selectionAttributes[];
nonSelectionAttributes: ProductVariantDetails_productVariant_nonSelectionAttributes[];
images: (ProductVariantDetails_productVariant_images | null)[] | null; images: (ProductVariantDetails_productVariant_images | null)[] | null;
name: string; name: string;
product: ProductVariantDetails_productVariant_product; product: ProductVariantDetails_productVariant_product;

View file

@ -14,11 +14,18 @@ export interface ProductVariantReorder_productVariantReorder_errors {
field: string | null; field: string | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantReorder_productVariantReorder_product_attributes_attribute_values { export interface ProductVariantReorder_productVariantReorder_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantReorder_productVariantReorder_product_attributes_attribute_values_file | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_attributes_attribute { export interface ProductVariantReorder_productVariantReorder_product_attributes_attribute {
@ -31,11 +38,18 @@ export interface ProductVariantReorder_productVariantReorder_product_attributes_
values: (ProductVariantReorder_productVariantReorder_product_attributes_attribute_values | null)[] | null; values: (ProductVariantReorder_productVariantReorder_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantReorder_productVariantReorder_product_attributes_values { export interface ProductVariantReorder_productVariantReorder_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantReorder_productVariantReorder_product_attributes_values_file | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_attributes { export interface ProductVariantReorder_productVariantReorder_product_attributes {
@ -44,11 +58,18 @@ export interface ProductVariantReorder_productVariantReorder_product_attributes
values: (ProductVariantReorder_productVariantReorder_product_attributes_values | null)[]; values: (ProductVariantReorder_productVariantReorder_product_attributes_values | null)[];
} }
export interface ProductVariantReorder_productVariantReorder_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantReorder_productVariantReorder_product_productType_variantAttributes_values { export interface ProductVariantReorder_productVariantReorder_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantReorder_productVariantReorder_product_productType_variantAttributes_values_file | null;
} }
export interface ProductVariantReorder_productVariantReorder_product_productType_variantAttributes { export interface ProductVariantReorder_productVariantReorder_product_productType_variantAttributes {

View file

@ -14,11 +14,18 @@ export interface ProductVariantSetDefault_productVariantSetDefault_errors {
field: string | null; field: string | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute_values { export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute_values_file | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute { export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute {
@ -31,11 +38,18 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product_attri
values: (ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute_values | null)[] | null; values: (ProductVariantSetDefault_productVariantSetDefault_product_attributes_attribute_values | null)[] | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_values { export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantSetDefault_productVariantSetDefault_product_attributes_values_file | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes { export interface ProductVariantSetDefault_productVariantSetDefault_product_attributes {
@ -44,11 +58,18 @@ export interface ProductVariantSetDefault_productVariantSetDefault_product_attri
values: (ProductVariantSetDefault_productVariantSetDefault_product_attributes_values | null)[]; values: (ProductVariantSetDefault_productVariantSetDefault_product_attributes_values | null)[];
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes_values { export interface ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes_values_file | null;
} }
export interface ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes { export interface ProductVariantSetDefault_productVariantSetDefault_product_productType_variantAttributes {

View file

@ -15,11 +15,18 @@ export interface SimpleProductUpdate_productUpdate_errors {
attributes: string[] | null; attributes: string[] | null;
} }
export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values { export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productUpdate_product_attributes_attribute_values_file | null;
} }
export interface SimpleProductUpdate_productUpdate_product_attributes_attribute { export interface SimpleProductUpdate_productUpdate_product_attributes_attribute {
@ -32,11 +39,18 @@ export interface SimpleProductUpdate_productUpdate_product_attributes_attribute
values: (SimpleProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; values: (SimpleProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null;
} }
export interface SimpleProductUpdate_productUpdate_product_attributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productUpdate_product_attributes_values { export interface SimpleProductUpdate_productUpdate_product_attributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productUpdate_product_attributes_values_file | null;
} }
export interface SimpleProductUpdate_productUpdate_product_attributes { export interface SimpleProductUpdate_productUpdate_product_attributes {
@ -45,11 +59,18 @@ export interface SimpleProductUpdate_productUpdate_product_attributes {
values: (SimpleProductUpdate_productUpdate_product_attributes_values | null)[]; values: (SimpleProductUpdate_productUpdate_product_attributes_values | null)[];
} }
export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values { export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values_file | null;
} }
export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes { export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes {
@ -275,33 +296,92 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant_private
value: string; value: string;
} }
export interface SimpleProductUpdate_productVariantUpdate_productVariant_attributes_attribute_values { export interface SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface SimpleProductUpdate_productVariantUpdate_productVariant_attributes_attribute { export interface SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (SimpleProductUpdate_productVariantUpdate_productVariant_attributes_attribute_values | null)[] | null; values: (SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface SimpleProductUpdate_productVariantUpdate_productVariant_attributes_values { export interface SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_values_file | null;
} }
export interface SimpleProductUpdate_productVariantUpdate_productVariant_attributes { export interface SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantUpdate_productVariant_attributes_attribute; attribute: SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantUpdate_productVariant_attributes_values | null)[]; values: (SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes_values | null)[];
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values_file | null;
}
export interface SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface SimpleProductUpdate_productVariantUpdate_productVariant_images { export interface SimpleProductUpdate_productVariantUpdate_productVariant_images {
@ -450,7 +530,8 @@ export interface SimpleProductUpdate_productVariantUpdate_productVariant {
id: string; id: string;
metadata: (SimpleProductUpdate_productVariantUpdate_productVariant_metadata | null)[]; metadata: (SimpleProductUpdate_productVariantUpdate_productVariant_metadata | null)[];
privateMetadata: (SimpleProductUpdate_productVariantUpdate_productVariant_privateMetadata | null)[]; privateMetadata: (SimpleProductUpdate_productVariantUpdate_productVariant_privateMetadata | null)[];
attributes: SimpleProductUpdate_productVariantUpdate_productVariant_attributes[]; selectionAttributes: SimpleProductUpdate_productVariantUpdate_productVariant_selectionAttributes[];
nonSelectionAttributes: SimpleProductUpdate_productVariantUpdate_productVariant_nonSelectionAttributes[];
images: (SimpleProductUpdate_productVariantUpdate_productVariant_images | null)[] | null; images: (SimpleProductUpdate_productVariantUpdate_productVariant_images | null)[] | null;
name: string; name: string;
product: SimpleProductUpdate_productVariantUpdate_productVariant_product; product: SimpleProductUpdate_productVariantUpdate_productVariant_product;
@ -486,33 +567,92 @@ export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_p
value: string; value: string;
} }
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute_values { export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute { export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute_values | null)[] | null; values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_values { export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_values_file | null;
} }
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes { export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_attribute; attribute: SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes_values | null)[]; values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes_values | null)[];
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_values_file | null;
}
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_images { export interface SimpleProductUpdate_productVariantStocksCreate_productVariant_images {
@ -661,7 +801,8 @@ export interface SimpleProductUpdate_productVariantStocksCreate_productVariant {
id: string; id: string;
metadata: (SimpleProductUpdate_productVariantStocksCreate_productVariant_metadata | null)[]; metadata: (SimpleProductUpdate_productVariantStocksCreate_productVariant_metadata | null)[];
privateMetadata: (SimpleProductUpdate_productVariantStocksCreate_productVariant_privateMetadata | null)[]; privateMetadata: (SimpleProductUpdate_productVariantStocksCreate_productVariant_privateMetadata | null)[];
attributes: SimpleProductUpdate_productVariantStocksCreate_productVariant_attributes[]; selectionAttributes: SimpleProductUpdate_productVariantStocksCreate_productVariant_selectionAttributes[];
nonSelectionAttributes: SimpleProductUpdate_productVariantStocksCreate_productVariant_nonSelectionAttributes[];
images: (SimpleProductUpdate_productVariantStocksCreate_productVariant_images | null)[] | null; images: (SimpleProductUpdate_productVariantStocksCreate_productVariant_images | null)[] | null;
name: string; name: string;
product: SimpleProductUpdate_productVariantStocksCreate_productVariant_product; product: SimpleProductUpdate_productVariantStocksCreate_productVariant_product;
@ -696,33 +837,92 @@ export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_p
value: string; value: string;
} }
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute_values { export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute { export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute_values | null)[] | null; values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_values { export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_values_file | null;
} }
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes { export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_attribute; attribute: SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes_values | null)[]; values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes_values | null)[];
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_values_file | null;
}
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_images { export interface SimpleProductUpdate_productVariantStocksDelete_productVariant_images {
@ -871,7 +1071,8 @@ export interface SimpleProductUpdate_productVariantStocksDelete_productVariant {
id: string; id: string;
metadata: (SimpleProductUpdate_productVariantStocksDelete_productVariant_metadata | null)[]; metadata: (SimpleProductUpdate_productVariantStocksDelete_productVariant_metadata | null)[];
privateMetadata: (SimpleProductUpdate_productVariantStocksDelete_productVariant_privateMetadata | null)[]; privateMetadata: (SimpleProductUpdate_productVariantStocksDelete_productVariant_privateMetadata | null)[];
attributes: SimpleProductUpdate_productVariantStocksDelete_productVariant_attributes[]; selectionAttributes: SimpleProductUpdate_productVariantStocksDelete_productVariant_selectionAttributes[];
nonSelectionAttributes: SimpleProductUpdate_productVariantStocksDelete_productVariant_nonSelectionAttributes[];
images: (SimpleProductUpdate_productVariantStocksDelete_productVariant_images | null)[] | null; images: (SimpleProductUpdate_productVariantStocksDelete_productVariant_images | null)[] | null;
name: string; name: string;
product: SimpleProductUpdate_productVariantStocksDelete_productVariant_product; product: SimpleProductUpdate_productVariantStocksDelete_productVariant_product;
@ -907,33 +1108,92 @@ export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_p
value: string; value: string;
} }
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values { export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute { export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values | null)[] | null; values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_values { export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values_file | null;
} }
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes { export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_attribute; attribute: SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes_values | null)[]; values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values | null)[];
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values_file | null;
}
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute;
values: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_images { export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant_images {
@ -1082,7 +1342,8 @@ export interface SimpleProductUpdate_productVariantStocksUpdate_productVariant {
id: string; id: string;
metadata: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_metadata | null)[]; metadata: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_metadata | null)[];
privateMetadata: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_privateMetadata | null)[]; privateMetadata: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_privateMetadata | null)[];
attributes: SimpleProductUpdate_productVariantStocksUpdate_productVariant_attributes[]; selectionAttributes: SimpleProductUpdate_productVariantStocksUpdate_productVariant_selectionAttributes[];
nonSelectionAttributes: SimpleProductUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes[];
images: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_images | null)[] | null; images: (SimpleProductUpdate_productVariantStocksUpdate_productVariant_images | null)[] | null;
name: string; name: string;
product: SimpleProductUpdate_productVariantStocksUpdate_productVariant_product; product: SimpleProductUpdate_productVariantStocksUpdate_productVariant_product;

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { ProductVariantCreateInput, ProductErrorCode, WeightUnitsEnum } from "./../../types/globalTypes"; import { ProductVariantCreateInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: VariantCreate // GraphQL mutation operation: VariantCreate
@ -27,33 +27,92 @@ export interface VariantCreate_productVariantCreate_productVariant_privateMetada
value: string; value: string;
} }
export interface VariantCreate_productVariantCreate_productVariant_attributes_attribute_values { export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface VariantCreate_productVariantCreate_productVariant_attributes_attribute { export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (VariantCreate_productVariantCreate_productVariant_attributes_attribute_values | null)[] | null; values: (VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface VariantCreate_productVariantCreate_productVariant_attributes_values { export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantCreate_productVariantCreate_productVariant_selectionAttributes_values_file | null;
} }
export interface VariantCreate_productVariantCreate_productVariant_attributes { export interface VariantCreate_productVariantCreate_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: VariantCreate_productVariantCreate_productVariant_attributes_attribute; attribute: VariantCreate_productVariantCreate_productVariant_selectionAttributes_attribute;
values: (VariantCreate_productVariantCreate_productVariant_attributes_values | null)[]; values: (VariantCreate_productVariantCreate_productVariant_selectionAttributes_values | null)[];
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_values_file | null;
}
export interface VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_attribute;
values: (VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface VariantCreate_productVariantCreate_productVariant_images { export interface VariantCreate_productVariantCreate_productVariant_images {
@ -202,7 +261,8 @@ export interface VariantCreate_productVariantCreate_productVariant {
id: string; id: string;
metadata: (VariantCreate_productVariantCreate_productVariant_metadata | null)[]; metadata: (VariantCreate_productVariantCreate_productVariant_metadata | null)[];
privateMetadata: (VariantCreate_productVariantCreate_productVariant_privateMetadata | null)[]; privateMetadata: (VariantCreate_productVariantCreate_productVariant_privateMetadata | null)[];
attributes: VariantCreate_productVariantCreate_productVariant_attributes[]; selectionAttributes: VariantCreate_productVariantCreate_productVariant_selectionAttributes[];
nonSelectionAttributes: VariantCreate_productVariantCreate_productVariant_nonSelectionAttributes[];
images: (VariantCreate_productVariantCreate_productVariant_images | null)[] | null; images: (VariantCreate_productVariantCreate_productVariant_images | null)[] | null;
name: string; name: string;
product: VariantCreate_productVariantCreate_productVariant_product; product: VariantCreate_productVariantCreate_productVariant_product;

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { ProductErrorCode, WeightUnitsEnum } from "./../../types/globalTypes"; import { ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: VariantImageAssign // GraphQL mutation operation: VariantImageAssign
@ -26,33 +26,92 @@ export interface VariantImageAssign_variantImageAssign_productVariant_privateMet
value: string; value: string;
} }
export interface VariantImageAssign_variantImageAssign_productVariant_attributes_attribute_values { export interface VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface VariantImageAssign_variantImageAssign_productVariant_attributes_attribute { export interface VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (VariantImageAssign_variantImageAssign_productVariant_attributes_attribute_values | null)[] | null; values: (VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface VariantImageAssign_variantImageAssign_productVariant_attributes_values { export interface VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_values_file | null;
} }
export interface VariantImageAssign_variantImageAssign_productVariant_attributes { export interface VariantImageAssign_variantImageAssign_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: VariantImageAssign_variantImageAssign_productVariant_attributes_attribute; attribute: VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_attribute;
values: (VariantImageAssign_variantImageAssign_productVariant_attributes_values | null)[]; values: (VariantImageAssign_variantImageAssign_productVariant_selectionAttributes_values | null)[];
}
export interface VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_values_file | null;
}
export interface VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_attribute;
values: (VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface VariantImageAssign_variantImageAssign_productVariant_images { export interface VariantImageAssign_variantImageAssign_productVariant_images {
@ -201,7 +260,8 @@ export interface VariantImageAssign_variantImageAssign_productVariant {
id: string; id: string;
metadata: (VariantImageAssign_variantImageAssign_productVariant_metadata | null)[]; metadata: (VariantImageAssign_variantImageAssign_productVariant_metadata | null)[];
privateMetadata: (VariantImageAssign_variantImageAssign_productVariant_privateMetadata | null)[]; privateMetadata: (VariantImageAssign_variantImageAssign_productVariant_privateMetadata | null)[];
attributes: VariantImageAssign_variantImageAssign_productVariant_attributes[]; selectionAttributes: VariantImageAssign_variantImageAssign_productVariant_selectionAttributes[];
nonSelectionAttributes: VariantImageAssign_variantImageAssign_productVariant_nonSelectionAttributes[];
images: (VariantImageAssign_variantImageAssign_productVariant_images | null)[] | null; images: (VariantImageAssign_variantImageAssign_productVariant_images | null)[] | null;
name: string; name: string;
product: VariantImageAssign_variantImageAssign_productVariant_product; product: VariantImageAssign_variantImageAssign_productVariant_product;

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { ProductErrorCode, WeightUnitsEnum } from "./../../types/globalTypes"; import { ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: VariantImageUnassign // GraphQL mutation operation: VariantImageUnassign
@ -26,33 +26,92 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant_privat
value: string; value: string;
} }
export interface VariantImageUnassign_variantImageUnassign_productVariant_attributes_attribute_values { export interface VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface VariantImageUnassign_variantImageUnassign_productVariant_attributes_attribute { export interface VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (VariantImageUnassign_variantImageUnassign_productVariant_attributes_attribute_values | null)[] | null; values: (VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface VariantImageUnassign_variantImageUnassign_productVariant_attributes_values { export interface VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_values_file | null;
} }
export interface VariantImageUnassign_variantImageUnassign_productVariant_attributes { export interface VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: VariantImageUnassign_variantImageUnassign_productVariant_attributes_attribute; attribute: VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_attribute;
values: (VariantImageUnassign_variantImageUnassign_productVariant_attributes_values | null)[]; values: (VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes_values | null)[];
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_values_file | null;
}
export interface VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_attribute;
values: (VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface VariantImageUnassign_variantImageUnassign_productVariant_images { export interface VariantImageUnassign_variantImageUnassign_productVariant_images {
@ -201,7 +260,8 @@ export interface VariantImageUnassign_variantImageUnassign_productVariant {
id: string; id: string;
metadata: (VariantImageUnassign_variantImageUnassign_productVariant_metadata | null)[]; metadata: (VariantImageUnassign_variantImageUnassign_productVariant_metadata | null)[];
privateMetadata: (VariantImageUnassign_variantImageUnassign_productVariant_privateMetadata | null)[]; privateMetadata: (VariantImageUnassign_variantImageUnassign_productVariant_privateMetadata | null)[];
attributes: VariantImageUnassign_variantImageUnassign_productVariant_attributes[]; selectionAttributes: VariantImageUnassign_variantImageUnassign_productVariant_selectionAttributes[];
nonSelectionAttributes: VariantImageUnassign_variantImageUnassign_productVariant_nonSelectionAttributes[];
images: (VariantImageUnassign_variantImageUnassign_productVariant_images | null)[] | null; images: (VariantImageUnassign_variantImageUnassign_productVariant_images | null)[] | null;
name: string; name: string;
product: VariantImageUnassign_variantImageUnassign_productVariant_product; product: VariantImageUnassign_variantImageUnassign_productVariant_product;

View file

@ -2,7 +2,7 @@
/* eslint-disable */ /* eslint-disable */
// This file was automatically generated and should not be edited. // This file was automatically generated and should not be edited.
import { StockInput, AttributeValueInput, ProductErrorCode, WeightUnitsEnum, StockErrorCode } from "./../../types/globalTypes"; import { StockInput, AttributeValueInput, ProductErrorCode, AttributeInputTypeEnum, WeightUnitsEnum, StockErrorCode } from "./../../types/globalTypes";
// ==================================================== // ====================================================
// GraphQL mutation operation: VariantUpdate // GraphQL mutation operation: VariantUpdate
@ -27,33 +27,92 @@ export interface VariantUpdate_productVariantUpdate_productVariant_privateMetada
value: string; value: string;
} }
export interface VariantUpdate_productVariantUpdate_productVariant_attributes_attribute_values { export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface VariantUpdate_productVariantUpdate_productVariant_attributes_attribute { export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (VariantUpdate_productVariantUpdate_productVariant_attributes_attribute_values | null)[] | null; values: (VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface VariantUpdate_productVariantUpdate_productVariant_attributes_values { export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_values_file | null;
} }
export interface VariantUpdate_productVariantUpdate_productVariant_attributes { export interface VariantUpdate_productVariantUpdate_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: VariantUpdate_productVariantUpdate_productVariant_attributes_attribute; attribute: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_attribute;
values: (VariantUpdate_productVariantUpdate_productVariant_attributes_values | null)[]; values: (VariantUpdate_productVariantUpdate_productVariant_selectionAttributes_values | null)[];
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values_file | null;
}
export interface VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_attribute;
values: (VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface VariantUpdate_productVariantUpdate_productVariant_images { export interface VariantUpdate_productVariantUpdate_productVariant_images {
@ -202,7 +261,8 @@ export interface VariantUpdate_productVariantUpdate_productVariant {
id: string; id: string;
metadata: (VariantUpdate_productVariantUpdate_productVariant_metadata | null)[]; metadata: (VariantUpdate_productVariantUpdate_productVariant_metadata | null)[];
privateMetadata: (VariantUpdate_productVariantUpdate_productVariant_privateMetadata | null)[]; privateMetadata: (VariantUpdate_productVariantUpdate_productVariant_privateMetadata | null)[];
attributes: VariantUpdate_productVariantUpdate_productVariant_attributes[]; selectionAttributes: VariantUpdate_productVariantUpdate_productVariant_selectionAttributes[];
nonSelectionAttributes: VariantUpdate_productVariantUpdate_productVariant_nonSelectionAttributes[];
images: (VariantUpdate_productVariantUpdate_productVariant_images | null)[] | null; images: (VariantUpdate_productVariantUpdate_productVariant_images | null)[] | null;
name: string; name: string;
product: VariantUpdate_productVariantUpdate_productVariant_product; product: VariantUpdate_productVariantUpdate_productVariant_product;
@ -238,33 +298,92 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant_private
value: string; value: string;
} }
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values { export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values_file | null;
} }
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute { export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute {
__typename: "Attribute"; __typename: "Attribute";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean; valueRequired: boolean;
values: (VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute_values | null)[] | null; values: (VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute_values | null)[] | null;
} }
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes_values { export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values {
__typename: "AttributeValue"; __typename: "AttributeValue";
id: string; id: string;
name: string | null; name: string | null;
slug: string | null; slug: string | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values_file | null;
} }
export interface VariantUpdate_productVariantStocksUpdate_productVariant_attributes { export interface VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes {
__typename: "SelectedAttribute"; __typename: "SelectedAttribute";
attribute: VariantUpdate_productVariantStocksUpdate_productVariant_attributes_attribute; attribute: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_attribute;
values: (VariantUpdate_productVariantStocksUpdate_productVariant_attributes_values | null)[]; values: (VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes_values | null)[];
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values_file | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute {
__typename: "Attribute";
id: string;
name: string | null;
slug: string | null;
inputType: AttributeInputTypeEnum | null;
valueRequired: boolean;
values: (VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute_values | null)[] | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values_file {
__typename: "File";
url: string;
contentType: string | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values {
__typename: "AttributeValue";
id: string;
name: string | null;
slug: string | null;
file: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values_file | null;
}
export interface VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes {
__typename: "SelectedAttribute";
attribute: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_attribute;
values: (VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes_values | null)[];
} }
export interface VariantUpdate_productVariantStocksUpdate_productVariant_images { export interface VariantUpdate_productVariantStocksUpdate_productVariant_images {
@ -413,7 +532,8 @@ export interface VariantUpdate_productVariantStocksUpdate_productVariant {
id: string; id: string;
metadata: (VariantUpdate_productVariantStocksUpdate_productVariant_metadata | null)[]; metadata: (VariantUpdate_productVariantStocksUpdate_productVariant_metadata | null)[];
privateMetadata: (VariantUpdate_productVariantStocksUpdate_productVariant_privateMetadata | null)[]; privateMetadata: (VariantUpdate_productVariantStocksUpdate_productVariant_privateMetadata | null)[];
attributes: VariantUpdate_productVariantStocksUpdate_productVariant_attributes[]; selectionAttributes: VariantUpdate_productVariantStocksUpdate_productVariant_selectionAttributes[];
nonSelectionAttributes: VariantUpdate_productVariantStocksUpdate_productVariant_nonSelectionAttributes[];
images: (VariantUpdate_productVariantStocksUpdate_productVariant_images | null)[] | null; images: (VariantUpdate_productVariantStocksUpdate_productVariant_images | null)[] | null;
name: string; name: string;
product: VariantUpdate_productVariantStocksUpdate_productVariant_product; product: VariantUpdate_productVariantStocksUpdate_productVariant_product;

View file

@ -1,9 +1,15 @@
import { ChannelData } from "@saleor/channels/utils"; import { ChannelData } from "@saleor/channels/utils";
import {
AttributeInput,
VariantAttributeScope
} from "@saleor/components/Attributes";
import { MetadataFormData } from "@saleor/components/Metadata/types"; import { MetadataFormData } from "@saleor/components/Metadata/types";
import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField"; import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocompleteSelectField";
import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField";
import { ProductVariant } from "@saleor/fragments/types/ProductVariant"; import { ProductVariant } from "@saleor/fragments/types/ProductVariant";
import { FormsetAtomicData } from "@saleor/hooks/useFormset"; import { SelectedVariantAttributeFragment } from "@saleor/fragments/types/SelectedVariantAttributeFragment";
import { VariantAttributeFragment } from "@saleor/fragments/types/VariantAttributeFragment";
import { FormsetAtomicData, FormsetData } from "@saleor/hooks/useFormset";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { import {
ProductDetails_product, ProductDetails_product,
@ -14,9 +20,7 @@ import { SearchProductTypes_search_edges_node_productAttributes } from "@saleor/
import { StockInput } from "@saleor/types/globalTypes"; import { StockInput } from "@saleor/types/globalTypes";
import { mapMetadataItemToInput } from "@saleor/utils/maps"; import { mapMetadataItemToInput } from "@saleor/utils/maps";
import { ProductAttributeInput } from "../components/ProductAttributes";
import { ProductStockInput } from "../components/ProductStocks"; import { ProductStockInput } from "../components/ProductStocks";
import { VariantAttributeInput } from "../components/ProductVariantAttributes";
import { ProductVariantCreateData_product } from "../types/ProductVariantCreateData"; import { ProductVariantCreateData_product } from "../types/ProductVariantCreateData";
export interface Collection { export interface Collection {
@ -38,13 +42,14 @@ export interface ProductType {
export function getAttributeInputFromProduct( export function getAttributeInputFromProduct(
product: ProductDetails_product product: ProductDetails_product
): ProductAttributeInput[] { ): AttributeInput[] {
return maybe( return maybe(
(): ProductAttributeInput[] => (): AttributeInput[] =>
product.attributes.map(attribute => ({ product.attributes.map(attribute => ({
data: { data: {
inputType: attribute.attribute.inputType, inputType: attribute.attribute.inputType,
isRequired: attribute.attribute.valueRequired, isRequired: attribute.attribute.valueRequired,
selectedValues: attribute.values,
values: attribute.attribute.values values: attribute.attribute.values
}, },
id: attribute.attribute.id, id: attribute.attribute.id,
@ -77,7 +82,7 @@ export function getSelectedAttributesFromProduct(
export function getAttributeInputFromProductType( export function getAttributeInputFromProductType(
productType: ProductType productType: ProductType
): ProductAttributeInput[] { ): AttributeInput[] {
return productType.productAttributes.map(attribute => ({ return productType.productAttributes.map(attribute => ({
data: { data: {
inputType: attribute.inputType, inputType: attribute.inputType,
@ -90,20 +95,73 @@ export function getAttributeInputFromProductType(
})); }));
} }
export function getAttributeInputFromAttributes(
variantAttributes: VariantAttributeFragment[],
variantAttributeScope: VariantAttributeScope
): AttributeInput[] {
return variantAttributes?.map(attribute => ({
data: {
inputType: attribute.inputType,
isRequired: attribute.valueRequired,
values: attribute.values,
variantAttributeScope
},
id: attribute.id,
label: attribute.name,
value: [""]
}));
}
export function getAttributeInputFromSelectedAttributes(
variantAttributes: SelectedVariantAttributeFragment[],
variantAttributeScope: VariantAttributeScope
): AttributeInput[] {
return variantAttributes?.map(attribute => ({
data: {
inputType: attribute.attribute.inputType,
isRequired: attribute.attribute.valueRequired,
selectedValues: attribute.values,
values: attribute.attribute.values,
variantAttributeScope
},
id: attribute.attribute.id,
label: attribute.attribute.name,
value: [(attribute.values.length && attribute.values[0]?.slug) || null]
}));
}
export function getAttributeInputFromVariant( export function getAttributeInputFromVariant(
variant: ProductVariant variant: ProductVariant
): VariantAttributeInput[] { ): AttributeInput[] {
return maybe( const selectionAttributeInput = getAttributeInputFromSelectedAttributes(
(): VariantAttributeInput[] => variant?.selectionAttributes,
variant.attributes.map(attribute => ({ VariantAttributeScope.VARIANT_SELECTION
data: { );
values: attribute.attribute.values const nonSelectionAttributeInput = getAttributeInputFromSelectedAttributes(
}, variant?.nonSelectionAttributes,
id: attribute.attribute.id, VariantAttributeScope.NOT_VARIANT_SELECTION
label: attribute.attribute.name, );
value: maybe(() => attribute.values[0].slug, null)
})), return (
[] selectionAttributeInput?.concat(nonSelectionAttributeInput ?? []) ?? []
);
}
export function getVariantAttributeInputFromProduct(
product: ProductVariantCreateData_product
): AttributeInput[] {
const selectionAttributeInput = getAttributeInputFromAttributes(
product?.productType?.selectionVariantAttributes,
VariantAttributeScope.VARIANT_SELECTION
);
const nonSelectionAttributeInput = getAttributeInputFromAttributes(
product?.productType?.nonSelectionVariantAttributes,
VariantAttributeScope.NOT_VARIANT_SELECTION
);
return (
selectionAttributeInput?.concat(nonSelectionAttributeInput ?? []) ?? []
); );
} }
@ -122,19 +180,6 @@ export function getStockInputFromVariant(
); );
} }
export function getVariantAttributeInputFromProduct(
product: ProductVariantCreateData_product
): VariantAttributeInput[] {
return product?.productType?.variantAttributes?.map(attribute => ({
data: {
values: attribute.values
},
id: attribute.id,
label: attribute.name,
value: ""
}));
}
export function getStockInputFromProduct( export function getStockInputFromProduct(
product: ProductDetails_product product: ProductDetails_product
): ProductStockInput[] { ): ProductStockInput[] {
@ -172,6 +217,26 @@ export function getChoices(nodes: Node[]): SingleAutocompleteChoiceType[] {
); );
} }
export const getAttributesDisplayData = (
attributes: AttributeInput[],
attributesWithNewFileValue: FormsetData<null, File>
) =>
attributes.map(attribute => {
const attributeWithNewFileValue = attributesWithNewFileValue.find(
attributeWithNewFile => attribute.id === attributeWithNewFile.id
);
if (attributeWithNewFileValue) {
return {
...attribute,
value: attributeWithNewFileValue?.value?.name
? [attributeWithNewFileValue.value.name]
: []
};
}
return attribute;
});
export interface ProductUpdatePageFormData extends MetadataFormData { export interface ProductUpdatePageFormData extends MetadataFormData {
category: string | null; category: string | null;
changeTaxCode: boolean; changeTaxCode: boolean;

View file

@ -1,10 +1,10 @@
import { AttributeInputData } from "@saleor/components/Attributes";
import { FormsetData } from "@saleor/hooks/useFormset"; import { FormsetData } from "@saleor/hooks/useFormset";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { ProductAttributeInputData } from "../components/ProductAttributes";
import { createAttributeMultiChangeHandler } from "./handlers"; import { createAttributeMultiChangeHandler } from "./handlers";
const attributes: FormsetData<ProductAttributeInputData, string[]> = [ const attributes: FormsetData<AttributeInputData, string[]> = [
{ {
data: { data: {
inputType: AttributeInputTypeEnum.DROPDOWN, inputType: AttributeInputTypeEnum.DROPDOWN,
@ -12,6 +12,7 @@ const attributes: FormsetData<ProductAttributeInputData, string[]> = [
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-1", id: "attrv-1",
name: "Attribute 1 Value 1", name: "Attribute 1 Value 1",
slug: "attr-1-v-1" slug: "attr-1-v-1"
@ -29,18 +30,21 @@ const attributes: FormsetData<ProductAttributeInputData, string[]> = [
values: [ values: [
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-2", id: "attrv-2",
name: "Attribute 2 Value 1", name: "Attribute 2 Value 1",
slug: "attr-2-v-1" slug: "attr-2-v-1"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-3", id: "attrv-3",
name: "Attribute 2 Value 2", name: "Attribute 2 Value 2",
slug: "attr-2-v-2" slug: "attr-2-v-2"
}, },
{ {
__typename: "AttributeValue", __typename: "AttributeValue",
file: null,
id: "attrv-4", id: "attrv-4",
name: "Attribute 2 Value 3", name: "Attribute 2 Value 3",
slug: "attr-2-v-3" slug: "attr-2-v-3"
@ -50,6 +54,28 @@ const attributes: FormsetData<ProductAttributeInputData, string[]> = [
id: "attr-2", id: "attr-2",
label: "Attribute 2", label: "Attribute 2",
value: ["attr-2-v-3"] value: ["attr-2-v-3"]
},
{
data: {
inputType: AttributeInputTypeEnum.FILE,
isRequired: false,
values: [
{
__typename: "AttributeValue",
file: {
__typename: "File",
contentType: "image/png",
url: "some-non-existing-url"
},
id: "attrv-5",
name: "File First Value",
slug: "file-first-value"
}
]
},
id: "attr-3",
label: "File Attribute",
value: []
} }
]; ];

View file

@ -3,11 +3,15 @@ import {
ChannelPriceArgs, ChannelPriceArgs,
ChannelPriceData ChannelPriceData
} from "@saleor/channels/utils"; } from "@saleor/channels/utils";
import { AttributeInputData } from "@saleor/components/Attributes";
import { FormChange } from "@saleor/hooks/useForm"; import { FormChange } from "@saleor/hooks/useForm";
import { FormsetChange, FormsetData } from "@saleor/hooks/useFormset"; import {
FormsetAtomicData,
FormsetChange,
FormsetData
} from "@saleor/hooks/useFormset";
import { toggle } from "@saleor/utils/lists"; import { toggle } from "@saleor/utils/lists";
import { ProductAttributeInputData } from "../components/ProductAttributes";
import { getAttributeInputFromProductType, ProductType } from "./data"; import { getAttributeInputFromProductType, ProductType } from "./data";
export function createAttributeChangeHandler( export function createAttributeChangeHandler(
@ -101,7 +105,7 @@ export function createVariantChannelsChangeHandler(
export function createAttributeMultiChangeHandler( export function createAttributeMultiChangeHandler(
changeAttributeData: FormsetChange<string[]>, changeAttributeData: FormsetChange<string[]>,
attributes: FormsetData<ProductAttributeInputData, string[]>, attributes: FormsetData<AttributeInputData, string[]>,
triggerChange: () => void triggerChange: () => void
): FormsetChange<string> { ): FormsetChange<string> {
return (attributeId: string, value: string) => { return (attributeId: string, value: string) => {
@ -120,8 +124,37 @@ export function createAttributeMultiChangeHandler(
}; };
} }
export function createAttributeFileChangeHandler(
changeAttributeData: FormsetChange<string[]>,
attributesWithNewFileValue: FormsetData<FormsetData<null, File>>,
addAttributeNewFileValue: (data: FormsetAtomicData<null, File>) => void,
changeAttributeNewFileValue: FormsetChange<File>,
triggerChange: () => void
): FormsetChange<File> {
return (attributeId: string, value: File) => {
triggerChange();
const newFileValueAssigned = attributesWithNewFileValue.find(
attribute => attribute.id === attributeId
);
if (newFileValueAssigned) {
changeAttributeNewFileValue(attributeId, value);
} else {
addAttributeNewFileValue({
data: null,
id: attributeId,
label: null,
value
});
}
changeAttributeData(attributeId, value ? [value.name] : []);
};
}
export function createProductTypeSelectHandler( export function createProductTypeSelectHandler(
setAttributes: (data: FormsetData<ProductAttributeInputData>) => void, setAttributes: (data: FormsetData<AttributeInputData>) => void,
setProductType: (productType: ProductType) => void, setProductType: (productType: ProductType) => void,
productTypeChoiceList: ProductType[], productTypeChoiceList: ProductType[],
triggerChange: () => void triggerChange: () => void

View file

@ -4,6 +4,7 @@ import { ChannelData, createSortedChannelsData } from "@saleor/channels/utils";
import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog"; import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog";
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config";
import { useFileUploadMutation } from "@saleor/files/mutations";
import useChannels from "@saleor/hooks/useChannels"; import useChannels from "@saleor/hooks/useChannels";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
@ -124,6 +125,8 @@ export const ProductCreateView: React.FC<ProductCreateProps> = ({ params }) => {
navigate(productUrl(productId)); navigate(productUrl(productId));
}; };
const [uploadFile, uploadFileOpts] = useFileUploadMutation({});
const [updateChannels, updateChannelsOpts] = useProductChannelListingUpdate( const [updateChannels, updateChannelsOpts] = useProductChannelListingUpdate(
{} {}
); );
@ -157,6 +160,7 @@ export const ProductCreateView: React.FC<ProductCreateProps> = ({ params }) => {
const result = await createMetadataCreateHandler( const result = await createMetadataCreateHandler(
createHandler( createHandler(
productTypes, productTypes,
variables => uploadFile({ variables }),
variables => productCreate({ variables }), variables => productCreate({ variables }),
variables => productVariantCreate({ variables }), variables => productVariantCreate({ variables }),
updateChannels, updateChannels,
@ -214,7 +218,8 @@ export const ProductCreateView: React.FC<ProductCreateProps> = ({ params }) => {
collections={(searchCollectionOpts?.data?.search?.edges || []).map( collections={(searchCollectionOpts?.data?.search?.edges || []).map(
edge => edge.node edge => edge.node
)} )}
disabled={ loading={
uploadFileOpts.loading ||
productCreateOpts.loading || productCreateOpts.loading ||
productVariantCreateOpts.loading || productVariantCreateOpts.loading ||
updateChannelsOpts.loading || updateChannelsOpts.loading ||

View file

@ -1,4 +1,18 @@
import {
getAttributesAfterFileAttributesUpdate,
mergeFileUploadErrors
} from "@saleor/attributes/utils/data";
import {
handleUploadMultipleFiles,
prepareAttributesInput
} from "@saleor/attributes/utils/handlers";
import { ChannelData } from "@saleor/channels/utils"; import { ChannelData } from "@saleor/channels/utils";
import {
FileUpload,
FileUploadVariables
} from "@saleor/files/types/FileUpload";
import { AttributeErrorFragment } from "@saleor/fragments/types/AttributeErrorFragment";
import { UploadErrorFragment } from "@saleor/fragments/types/UploadErrorFragment";
import { weight } from "@saleor/misc"; import { weight } from "@saleor/misc";
import { ProductCreateData } from "@saleor/products/components/ProductCreatePage/form"; import { ProductCreateData } from "@saleor/products/components/ProductCreatePage/form";
import { import {
@ -52,6 +66,9 @@ const getSimpleProductVariables = (
export function createHandler( export function createHandler(
productTypes: SearchProductTypes_search_edges_node[], productTypes: SearchProductTypes_search_edges_node[],
uploadFile: (
variables: FileUploadVariables
) => Promise<MutationFetchResult<FileUpload>>,
productCreate: ( productCreate: (
variables: ProductCreateVariables variables: ProductCreateVariables
) => Promise<MutationFetchResult<ProductCreate>>, ) => Promise<MutationFetchResult<ProductCreate>>,
@ -69,12 +86,25 @@ export function createHandler(
}) => Promise<MutationFetchResult<ProductDelete>> }) => Promise<MutationFetchResult<ProductDelete>>
) { ) {
return async (formData: ProductCreateData) => { return async (formData: ProductCreateData) => {
let errors: Array<AttributeErrorFragment | UploadErrorFragment> = [];
const uploadFilesResult = await handleUploadMultipleFiles(
formData.attributesWithNewFileValue,
uploadFile
);
errors = [...errors, ...mergeFileUploadErrors(uploadFilesResult)];
const updatedFileAttributes = getAttributesAfterFileAttributesUpdate(
formData.attributesWithNewFileValue,
uploadFilesResult
);
const productVariables: ProductCreateVariables = { const productVariables: ProductCreateVariables = {
input: { input: {
attributes: formData.attributes.map(attribute => ({ attributes: prepareAttributesInput({
id: attribute.id, attributes: formData.attributes,
values: attribute.value updatedFileAttributes
})), }),
category: formData.category, category: formData.category,
chargeTaxes: formData.chargeTaxes, chargeTaxes: formData.chargeTaxes,
collections: formData.collections, collections: formData.collections,
@ -93,12 +123,16 @@ export function createHandler(
}; };
const result = await productCreate(productVariables); const result = await productCreate(productVariables);
let hasErrors = false; let hasErrors = errors.length > 0;
const hasVariants = productTypes.find( const hasVariants = productTypes.find(
product => product.id === formData.productType.id product => product.id === formData.productType.id
).hasVariants; ).hasVariants;
const productId = result.data.productCreate.product.id; const productId = result.data.productCreate.product?.id;
if (!productId) {
return null;
}
if (!hasVariants) { if (!hasVariants) {
const result = await Promise.all([ const result = await Promise.all([
@ -142,7 +176,7 @@ export function createHandler(
A more robust solution would require merging create and update form into one to persist form state across redirects A more robust solution would require merging create and update form into one to persist form state across redirects
*/ */
if (productId && hasErrors) { if (productId && hasErrors) {
productDelete({ variables: { id: productId } }); await productDelete({ variables: { id: productId } });
return null; return null;
} }

Some files were not shown because too many files have changed in this diff Show more