Apps (#599)
* create Apps view * create more app components, generate types and messages * apps refactor, update snapshots * show error message in tooltip when app installation fail * update apps components and view, add apps list to storybook * update defaultMessages * create app details view * update AppListPage with Skeleton component * create app activate/deactivate dialogs, create app details stories * add AppHeader to AppDetailsPage * update defaultMessages * update AppDetails view and components after review * create custom app details view * refactor webhooks * update webhooks fixtures * update WebhookDetailsPage story * update strings * create CustomAppCreate view and components * update AppListPage story * create AppInstall view and page * handle errors in AppInstall view * update defaultMessages * add AppInstallPage to storybook * add status prop to MessageManager * update defaultMessages * remove service account section * remove service account routes * remove as operator from notify status * add notifications for app installations * update styles for deactivated app * update app installations with local storage * update defaultMessages * AppInstall update * dd delete button to ongoin installations table * fix active installations condition * fix error messages in AppsList * update defaultMessages * add iframe to AppDetailsPage * create AppDetailsSettingsPage * install macaw-ui * apps styles clean up * update schema, fixtures * few apps updates * WebhookCreate - fix onBack button name * WebhookCreatePage story update * rename apps table from external to thirdparty * update defaultMessages * fix test, update snapshots * AppDetailsSettings - add token to headers * fix first number in local apps query * app details settings - use shop domain host * add onSettingsRowClick to InstalledApps * resolve conflicts * update changelog and messages * add noopener noreferrer do app privacy link * update snapshots * update snapshots * updates after review * update defaultMessages * CustomAppDetails - add missing notify status
|
@ -12,6 +12,7 @@ All notable, unreleased changes to this project will be documented in this file.
|
|||
- Move fragments to separate directory to avoid circular imports - #592 by @dominik-zeglen
|
||||
- Add order invoices management - #570 by @orzechdev
|
||||
- Add Cypress e2e runner - #584 by @krzysztofwolski
|
||||
- create Apps - #599 by @AlicjaSzu
|
||||
|
||||
## 2.10.1
|
||||
|
||||
|
|
4
assets/images/activate-icon.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="24" height="24"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 22.5C17.799 22.5 22.5 17.799 22.5 12C22.5 6.20101 17.799 1.5 12 1.5C6.20101 1.5 1.5 6.20101 1.5 12C1.5 17.799 6.20101 22.5 12 22.5ZM12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24ZM9.75 5.53473C7.07559 6.46535 5.15625 9.00854 5.15625 12C5.15625 15.7797 8.2203 18.8438 12 18.8438C15.7797 18.8438 18.8438 15.7797 18.8438 12C18.8438 8.9737 16.8794 6.40617 14.1562 5.50287V7.10915C16.0335 7.938 17.3438 9.816 17.3438 12C17.3438 14.9513 14.9513 17.3438 12 17.3438C9.04873 17.3438 6.65625 14.9513 6.65625 12C6.65625 9.85254 7.92298 8.00093 9.75 7.15163V5.53473ZM11.25 4.125V11.1562H12.75V4.125H11.25Z" fill="#06847B"/>
|
||||
</svg>
|
After Width: | Height: | Size: 864 B |
36
assets/images/app-install-error.svg
Normal file
After Width: | Height: | Size: 35 KiB |
|
@ -1,5 +1,5 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
|
||||
<rect x="10.2726" y="9.00024" width="17.9987" height="1.79987" transform="rotate(45 10.2726 9.00024)" fill="#FE6D76"/>
|
||||
<rect x="23" y="10.2727" width="17.9987" height="1.79987" transform="rotate(135 23 10.2727)" fill="#FE6D76"/>
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
|
||||
<path fill="#FE6D76" d="M10.273 9L23 21.728 21.727 23 9 10.273z"/>
|
||||
<path fill="#FE6D76" d="M23 10.272L10.273 23 9 21.727 21.727 9z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 380 B After Width: | Height: | Size: 268 B |
3
assets/images/menu-apps-icon.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.375 1.625H1.625V12.375H12.375V1.625ZM0 0V14H14V0H0ZM12.375 19.625H1.625V30.375H12.375V19.625ZM0 18V32H14V18H0ZM19.625 19.625H30.375V30.375H19.625V19.625ZM18 32V18H32V32H18ZM24.25 2H25.875V6.125H30V7.75H25.875V11.875H24.25V7.75H20.125V6.125H24.25V2Z" fill="#3D3D3D"/>
|
||||
</svg>
|
After Width: | Height: | Size: 423 B |
4
assets/images/plus-icon.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="18" cy="18" r="17.5" fill="white" stroke="#EAEAEA"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19 10H17V17H10V19H17V26H19V19H26V17H19V10Z" fill="#06847B"/>
|
||||
</svg>
|
After Width: | Height: | Size: 279 B |
4
assets/images/settings-icon.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="24" height="24"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.2149 2L21 5.78505L18.6131 8.17192L14.8281 4.38686L17.2149 2ZM16.8054 4.38686L18.6131 6.19457L19.0227 5.78505L17.2149 3.97734L16.8054 4.38686ZM14.4186 4.79638L18.2036 8.58144L6.78505 20H3V16.2149L14.4186 4.79638ZM4.39819 16.7941V17.6131L5.38686 18.6018H6.2059L16.2263 8.58144L14.4186 6.77372L4.39819 16.7941Z" fill="#06847B"/>
|
||||
</svg>
|
After Width: | Height: | Size: 513 B |
3
assets/images/support-icon.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 7.58853L1.5 3.83853V10.5H16.5V3.83853L9 7.58853ZM18 12H0V0H18V12ZM16.5 1.5V2.16147L9 5.91147L1.5 2.16147V1.5H16.5Z" fill="#06847B"/>
|
||||
</svg>
|
After Width: | Height: | Size: 288 B |
|
@ -298,6 +298,357 @@
|
|||
"context": "button",
|
||||
"string": "Accept"
|
||||
},
|
||||
"src_dot_apps": {
|
||||
"context": "apps section name",
|
||||
"string": "Apps"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppActivateDialog_dot_1499521723": {
|
||||
"context": "dialog header",
|
||||
"string": "Activate App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppActivateDialog_dot_3356885734": {
|
||||
"context": "activate app",
|
||||
"string": "Are you sure you want to activate {name}? Activating will start gathering events."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppActivateDialog_dot_3761045983": {
|
||||
"context": "activate app",
|
||||
"string": "Are you sure you want to activate this app? Activating will start gathering events"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppActivateDialog_dot_3865193889": {
|
||||
"context": "button label",
|
||||
"string": "Activate"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeactivateDialog_dot_1782042241": {
|
||||
"context": "button label",
|
||||
"string": "Deactivate"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeactivateDialog_dot_2031792590": {
|
||||
"context": "dialog header",
|
||||
"string": "Dectivate App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeactivateDialog_dot_2955925498": {
|
||||
"context": "deactivate app",
|
||||
"string": "Are you sure you want to disable this app? Your data will be kept until you reactivate the app. You will be still billed for the app."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeactivateDialog_dot_329373780": {
|
||||
"context": "deactivate app",
|
||||
"string": "Are you sure you want to disable {name}? Your data will be kept until you reactivate the app. You will be still billed for the app."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeleteDialog_dot_1347203024": {
|
||||
"context": "delete custom app",
|
||||
"string": "Deleting {name}, you will delete all the data and webhooks regarding this app. Are you sure you want to do that?"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeleteDialog_dot_1462011531": {
|
||||
"context": "dialog header",
|
||||
"string": "Delete App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeleteDialog_dot_330001535": {
|
||||
"context": "delete app",
|
||||
"string": "Are you sure you want to delete this app?"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDeleteDialog_dot_3817179919": {
|
||||
"context": "delete app",
|
||||
"string": "Deleting {name}, you will remove installation of the app. If you are paying for app subscription, remember to unsubscribe from the app in Saleor Marketplace. Are you sure you want to delete the app?"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_1782042241": {
|
||||
"context": "link",
|
||||
"string": "Deactivate"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_2432433023": {
|
||||
"context": "app privacy policy link",
|
||||
"string": "View this app’s privacy policy"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_2973480575": {
|
||||
"context": "link",
|
||||
"string": "Edit settings"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_3744068622": {
|
||||
"context": "section header",
|
||||
"string": "Data privacy"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_3768793197": {
|
||||
"context": "link",
|
||||
"string": "Get Support"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_3817397882": {
|
||||
"context": "button",
|
||||
"string": "Open App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_3865193889": {
|
||||
"context": "link",
|
||||
"string": "Activate"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_3916538164": {
|
||||
"context": "section header",
|
||||
"string": "App permissions"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_846582072": {
|
||||
"context": "apps about permissions",
|
||||
"string": "This app has permissions to:"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsPage_dot_85811128": {
|
||||
"context": "section header",
|
||||
"string": "About this app"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsSettingsPage_dot_198187074": {
|
||||
"context": "button",
|
||||
"string": "Support/FAQ"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsSettingsPage_dot_3302125406": {
|
||||
"context": "button",
|
||||
"string": "My App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppDetailsSettingsPage_dot_3662390044": {
|
||||
"context": "button",
|
||||
"string": "Dashboard"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInProgressDeleteDialog_dot_1462011531": {
|
||||
"context": "dialog header",
|
||||
"string": "Delete App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInProgressDeleteDialog_dot_330001535": {
|
||||
"context": "delete app",
|
||||
"string": "Are you sure you want to delete this app?"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInProgressDeleteDialog_dot_3817179919": {
|
||||
"context": "delete app",
|
||||
"string": "Deleting {name}, you will remove installation of the app. If you are paying for app subscription, remember to unsubscribe from the app in Saleor Marketplace. Are you sure you want to delete the app?"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallErrorPage_dot_1152717819": {
|
||||
"context": "title",
|
||||
"string": "There’s a problem with app."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallErrorPage_dot_1261716527": {
|
||||
"context": "content",
|
||||
"string": "Saleor couldn’t fetch crucial information regarding installation. Without those System can’t install the app in your Saleor. Please use the button below to get back to system’s dashboard."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallErrorPage_dot_3375237564": {
|
||||
"context": "button",
|
||||
"string": "Back to homepage"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallPage_dot_127674832": {
|
||||
"context": "app data privacy link",
|
||||
"string": "Learn more about data privacy"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallPage_dot_2538706256": {
|
||||
"context": "install button",
|
||||
"string": "Install App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallPage_dot_2936990163": {
|
||||
"context": "install app permissions",
|
||||
"string": "Installing this app will give it following permissions:"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallPage_dot_3436300370": {
|
||||
"context": "install app privacy",
|
||||
"string": "Uninstalling the app will remove all your customer’s personal data stored by {name}. "
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallPage_dot_3688014441": {
|
||||
"context": "section header",
|
||||
"string": "You are about to install {name}"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppInstallPage_dot_3916538164": {
|
||||
"context": "section header",
|
||||
"string": "App permissions"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppsInProgress_dot_1675189051": {
|
||||
"context": "section header",
|
||||
"string": "Ongoing Installations"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppsInProgress_dot_2398081356": {
|
||||
"context": "retry installation",
|
||||
"string": "Retry"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppsInProgress_dot_2868351060": {
|
||||
"context": "app installation error",
|
||||
"string": "There was a problem during installation"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_AppsInProgress_dot_3733091754": {
|
||||
"context": "app installation",
|
||||
"string": "Installing app..."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppCreatePage_dot_1414896555": {
|
||||
"context": "checkbox label",
|
||||
"string": "Grant this app full access to the store"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppCreatePage_dot_3076071936": {
|
||||
"context": "card description",
|
||||
"string": "Expand or restrict app permissions to access certain part of Saleor system."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppCreatePage_dot_3189779214": {
|
||||
"context": "header",
|
||||
"string": "Create New App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppCreatePage_dot_570656367": {
|
||||
"context": "checkbox label",
|
||||
"string": "App is active"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDefaultToken_dot_1336855942": {
|
||||
"string": "Generated Token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDefaultToken_dot_2080322626": {
|
||||
"string": "This token gives you access to your shop's API, which you'll find here: {url}"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDefaultToken_dot_2864204643": {
|
||||
"context": "button",
|
||||
"string": "Copied"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDefaultToken_dot_3406541221": {
|
||||
"context": "button",
|
||||
"string": "Copy token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDefaultToken_dot_4189999598": {
|
||||
"string": "We’ve created your default token. Make sure to copy your new personal access token now. You won’t be able to see it again."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDetailsPage_dot_1414896555": {
|
||||
"context": "checkbox label",
|
||||
"string": "Grant this app full access to the store"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDetailsPage_dot_3076071936": {
|
||||
"context": "card description",
|
||||
"string": "Expand or restrict app permissions to access certain part of Saleor system."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppDetailsPage_dot_570656367": {
|
||||
"context": "checkbox label",
|
||||
"string": "App is active"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppInformation_dot_2860466085": {
|
||||
"context": "header",
|
||||
"string": "App Information"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppInformation_dot_3001692357": {
|
||||
"context": "custom app name",
|
||||
"string": "App Name"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppTokens_dot_2446088470": {
|
||||
"context": "custom app token key",
|
||||
"string": "Key"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppTokens_dot_2639089057": {
|
||||
"string": "No tokens found"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppTokens_dot_3209034045": {
|
||||
"context": "header",
|
||||
"string": "Tokens"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppTokens_dot_3875340101": {
|
||||
"context": "button",
|
||||
"string": "Create Token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppTokens_dot_4017491013": {
|
||||
"string": "Token Note"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomAppTokens_dot_4190792473": {
|
||||
"context": "table actions",
|
||||
"string": "Actions"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomApps_dot_3152347892": {
|
||||
"context": "custom apps content",
|
||||
"string": "Your custom created apps will be shown here."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_CustomApps_dot_3230241731": {
|
||||
"context": "create app button",
|
||||
"string": "Create App"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_DeactivatedText_dot_3064552173": {
|
||||
"context": "app deactivated",
|
||||
"string": "Deactivated"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_InstalledApps_dot_1636202177": {
|
||||
"context": "about app",
|
||||
"string": "About"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_InstalledApps_dot_186286611": {
|
||||
"context": "apps content",
|
||||
"string": "You don’t have any installed apps in your dashboard"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_InstalledApps_dot_2008086393": {
|
||||
"context": "section header",
|
||||
"string": "Thirdparty Apps"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_Marketplace_dot_2932910073": {
|
||||
"context": "section header",
|
||||
"string": "Saleor Marketplace"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_Marketplace_dot_3259214524": {
|
||||
"context": "marketplace content",
|
||||
"string": "Marketplace is coming soon"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_Marketplace_dot_3910026447": {
|
||||
"context": "marketplace button",
|
||||
"string": "Visit Marketplace"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_Marketplace_dot_52985091": {
|
||||
"context": "marketplace content",
|
||||
"string": "Discover great free and paid apps in our Saleor Marketplace."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_1336855942": {
|
||||
"string": "Generated Token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_2530792168": {
|
||||
"string": "Access token is used to authenticate service accounts"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_3009959880": {
|
||||
"string": "We’ve created your token. Make sure to copy your new personal access token now. You won’t be able to see it again."
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_3406541221": {
|
||||
"context": "button",
|
||||
"string": "Copy token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_3875340101": {
|
||||
"context": "header",
|
||||
"string": "Create Token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_4017491013": {
|
||||
"string": "Token Note"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenCreateDialog_dot_4120989039": {
|
||||
"context": "create service token, button",
|
||||
"string": "Create"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenDeleteDialog_dot_2164262076": {
|
||||
"context": "dialog title",
|
||||
"string": "Delete Token"
|
||||
},
|
||||
"src_dot_apps_dot_components_dot_TokenDeleteDialog_dot_981802752": {
|
||||
"context": "delete token",
|
||||
"string": "Are you sure you want to delete token {token}?"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppDetailsSettings_dot_2140018198": {
|
||||
"context": "app settings error",
|
||||
"string": "Failed to fetch app settings"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppDetails_dot_2021043385": {
|
||||
"context": "snackbar text",
|
||||
"string": "App activated"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppDetails_dot_3791371350": {
|
||||
"context": "snackbar text",
|
||||
"string": "App deactivated"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppInstall_dot_2538706256": {
|
||||
"context": "window title",
|
||||
"string": "Install App"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppsList_dot_1180774955": {
|
||||
"context": "app has been installed",
|
||||
"string": "{name} is ready to be used"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppsList_dot_3076215778": {
|
||||
"context": "app has been removed",
|
||||
"string": "App successfully removed"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppsList_dot_539268521": {
|
||||
"context": "message title",
|
||||
"string": "Couldn’t Install {name}"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_AppsList_dot_966773578": {
|
||||
"context": "message title",
|
||||
"string": "App installed"
|
||||
},
|
||||
"src_dot_apps_dot_views_dot_CustomAppCreate_dot_3230241731": {
|
||||
"context": "window title",
|
||||
"string": "Create App"
|
||||
},
|
||||
"src_dot_attributes": {
|
||||
"context": "attributes section name",
|
||||
"string": "Attributes"
|
||||
|
@ -931,13 +1282,6 @@
|
|||
"context": "permission list item description",
|
||||
"string": "This group is last source of that permission"
|
||||
},
|
||||
"src_dot_components_dot_AccountStatus_dot_2183517419": {
|
||||
"context": "section header",
|
||||
"string": "Account Status"
|
||||
},
|
||||
"src_dot_components_dot_AccountStatus_dot_2683780981": {
|
||||
"string": "If you want to disable this account uncheck the box below"
|
||||
},
|
||||
"src_dot_components_dot_AddressEdit_dot_1139500589": {
|
||||
"string": "Country"
|
||||
},
|
||||
|
@ -970,6 +1314,13 @@
|
|||
"context": "button",
|
||||
"string": "Account Settings"
|
||||
},
|
||||
"src_dot_components_dot_AppStatus_dot_1624959454": {
|
||||
"string": "If you want to disable this App please uncheck the box below."
|
||||
},
|
||||
"src_dot_components_dot_AppStatus_dot_1750277107": {
|
||||
"context": "section header",
|
||||
"string": "App Status"
|
||||
},
|
||||
"src_dot_components_dot_AssignCategoryDialog_dot_1305061437": {
|
||||
"string": "Search Categories"
|
||||
},
|
||||
|
@ -1442,15 +1793,9 @@
|
|||
"src_dot_configuration_dot_1440737903": {
|
||||
"string": "Shipping Settings"
|
||||
},
|
||||
"src_dot_configuration_dot_1639245766": {
|
||||
"string": "View and update your webhook and their settings"
|
||||
},
|
||||
"src_dot_configuration_dot_1742602794": {
|
||||
"string": "Attributes and Product Types"
|
||||
},
|
||||
"src_dot_configuration_dot_2387898569": {
|
||||
"string": "Manage external integrations accounts"
|
||||
},
|
||||
"src_dot_configuration_dot_3140151600": {
|
||||
"string": "Staff Settings"
|
||||
},
|
||||
|
@ -1476,6 +1821,9 @@
|
|||
"context": "button",
|
||||
"string": "Create"
|
||||
},
|
||||
"src_dot_customApps": {
|
||||
"string": "Local Apps"
|
||||
},
|
||||
"src_dot_customers": {
|
||||
"context": "customers section name",
|
||||
"string": "Customers"
|
||||
|
@ -4090,159 +4438,6 @@
|
|||
"context": "service accounts section name",
|
||||
"string": "Service Accounts"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceCreatePage_dot_1848599267": {
|
||||
"context": "checkbox label",
|
||||
"string": "User has full access to the store"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceCreatePage_dot_248507553": {
|
||||
"context": "header",
|
||||
"string": "Create New Account"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceCreatePage_dot_27827485": {
|
||||
"context": "checkbox label",
|
||||
"string": "Service account is active"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceCreatePage_dot_3639008725": {
|
||||
"context": "card description",
|
||||
"string": "Expand or restrict user's permissions to access certain part of saleor system."
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDefaultToken_dot_1336855942": {
|
||||
"string": "Generated Token"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDefaultToken_dot_2080322626": {
|
||||
"string": "This token gives you access to your shop's API, which you'll find here: {url}"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDefaultToken_dot_2864204643": {
|
||||
"context": "button",
|
||||
"string": "Copied"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDefaultToken_dot_3406541221": {
|
||||
"context": "button",
|
||||
"string": "Copy token"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDefaultToken_dot_4189999598": {
|
||||
"string": "We’ve created your default token. Make sure to copy your new personal access token now. You won’t be able to see it again."
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDeleteDialog_dot_1534767622": {
|
||||
"context": "dialog header",
|
||||
"string": "Delete Service Account"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDeleteDialog_dot_2297471173": {
|
||||
"context": "delete service account",
|
||||
"string": "Are you sure you want to delete {name}?"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDetailsPage_dot_1848599267": {
|
||||
"context": "checkbox label",
|
||||
"string": "User has full access to the store"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDetailsPage_dot_27827485": {
|
||||
"context": "checkbox label",
|
||||
"string": "Service account is active"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceDetailsPage_dot_3639008725": {
|
||||
"context": "card description",
|
||||
"string": "Expand or restrict user's permissions to access certain part of saleor system."
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceInfo_dot_3789449123": {
|
||||
"context": "service account",
|
||||
"string": "Account Name"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceInfo_dot_426959482": {
|
||||
"context": "header",
|
||||
"string": "Service Account Information"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceListPage_dot_1895355592": {
|
||||
"string": "Search Service Accounts"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceListPage_dot_4040605455": {
|
||||
"context": "tab name",
|
||||
"string": "All Service Accounts"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceListPage_dot_624280156": {
|
||||
"context": "button",
|
||||
"string": "Create account"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceListPage_dot_active": {
|
||||
"context": "service account",
|
||||
"string": "Active"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceListPage_dot_deactivated": {
|
||||
"context": "service account",
|
||||
"string": "Inactive"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceList_dot_1342308051": {
|
||||
"string": "No service accounts found"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceList_dot_31853942": {
|
||||
"context": "account status",
|
||||
"string": "active"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceList_dot_3239722049": {
|
||||
"context": "account status",
|
||||
"string": "inactive"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceList_dot_636461959": {
|
||||
"context": "service name",
|
||||
"string": "Name"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_1336855942": {
|
||||
"string": "Generated Token"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_2530792168": {
|
||||
"string": "Access token is used to authenticate service accounts"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_3009959880": {
|
||||
"string": "We’ve created your token. Make sure to copy your new personal access token now. You won’t be able to see it again."
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_3406541221": {
|
||||
"context": "button",
|
||||
"string": "Copy token"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_3875340101": {
|
||||
"context": "header",
|
||||
"string": "Create Token"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_4017491013": {
|
||||
"string": "Token Note"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenCreateDialog_dot_4120989039": {
|
||||
"context": "create service token, button",
|
||||
"string": "Create"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenDeleteDialog_dot_1534767622": {
|
||||
"context": "dialog title",
|
||||
"string": "Delete Service Account"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokenDeleteDialog_dot_981802752": {
|
||||
"context": "delete token",
|
||||
"string": "Are you sure you want to delete token {token}?"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokens_dot_2446088470": {
|
||||
"context": "service account key",
|
||||
"string": "Key"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokens_dot_2639089057": {
|
||||
"string": "No tokens found"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokens_dot_3875340101": {
|
||||
"context": "button",
|
||||
"string": "Create Token"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokens_dot_4017491013": {
|
||||
"string": "Token Note"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokens_dot_4190792473": {
|
||||
"context": "table actions",
|
||||
"string": "Actions"
|
||||
},
|
||||
"src_dot_services_dot_components_dot_ServiceTokens_dot_426959482": {
|
||||
"context": "header",
|
||||
"string": "Service Account Information"
|
||||
},
|
||||
"src_dot_services_dot_views_dot_ServiceCreate_dot_3167211165": {
|
||||
"context": "window title",
|
||||
"string": "Create Service Account"
|
||||
},
|
||||
"src_dot_sessionExpired": {
|
||||
"string": "Your session has expired. Please log in again to continue."
|
||||
},
|
||||
|
@ -5189,12 +5384,21 @@
|
|||
"src_dot_utils_dot_errors_dot_invalid": {
|
||||
"string": "Invalid value"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_invalidManifestFormat": {
|
||||
"string": "Invalid manifest format"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_invalidPassword": {
|
||||
"string": "Invalid password"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_invalidPermission": {
|
||||
"string": "Permission is invalid"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_invalidStatus": {
|
||||
"context": "error message",
|
||||
"string": "Cannot request an invoice for draft order"
|
||||
"string": "Status is invalid"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_invalidUrlFormat": {
|
||||
"string": "Url has invalid format"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_noShippingAddress": {
|
||||
"context": "error message",
|
||||
|
@ -5216,9 +5420,15 @@
|
|||
"context": "error message",
|
||||
"string": "Number not set for an invoice"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_outOfScopeApp": {
|
||||
"string": "App is out of your permissions scope"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_outOfScopeGroup": {
|
||||
"string": "Group is out of your permission scope"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_outOfScopePermission": {
|
||||
"string": "Permission is out of your scope"
|
||||
},
|
||||
"src_dot_utils_dot_errors_dot_outOfScopeUser": {
|
||||
"string": "User is out of your permissions scope"
|
||||
},
|
||||
|
@ -5448,9 +5658,6 @@
|
|||
"context": "webhook specific information",
|
||||
"string": "Webhook specific information"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookInfo_dot_819389696": {
|
||||
"string": "Assign to Service Account"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookStatus_dot_2772025990": {
|
||||
"context": "webhooks active",
|
||||
"string": "Webhook is active"
|
||||
|
@ -5471,31 +5678,16 @@
|
|||
"context": "header",
|
||||
"string": "{webhookName} Details"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksListPage_dot_1432828311": {
|
||||
"string": "Search Webhooks"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksListPage_dot_2295583901": {
|
||||
"context": "button",
|
||||
"string": "Create webhook"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksListPage_dot_3300314452": {
|
||||
"context": "tab name",
|
||||
"string": "All Webhooks"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksListPage_dot_active": {
|
||||
"context": "webhook",
|
||||
"string": "Active"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksListPage_dot_inactive": {
|
||||
"context": "webhook",
|
||||
"string": "Inactive"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksList_dot_1153324159": {
|
||||
"string": "No webhooks found"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksList_dot_2487865635": {
|
||||
"context": "webhook service account",
|
||||
"string": "Service Account"
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksList_dot_3493926696": {
|
||||
"context": "button",
|
||||
"string": "Create Webhook"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksList_dot_3861572549": {
|
||||
"context": "header",
|
||||
"string": "Webhooks"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhooksList_dot_4120604650": {
|
||||
"context": "user action bar",
|
||||
|
|
387
package-lock.json
generated
|
@ -2735,6 +2735,31 @@
|
|||
"warning": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@saleor/macaw-ui": {
|
||||
"version": "0.1.1-9",
|
||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.1.1-9.tgz",
|
||||
"integrity": "sha512-ryftb0jBs1ghIm4ILwJZ7vfQt90Kab9XlNcEUh4JFDV4+HEABrGpwstLKyCtIjFDzxQf/z9L4vbW25o1m6klmg==",
|
||||
"requires": {
|
||||
"@types/react-inlinesvg": "^0.8.1",
|
||||
"classnames": "^2.2.6",
|
||||
"downshift": "^1.31.16",
|
||||
"lodash-es": "^4.17.15",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-inlinesvg": "^1.1.2",
|
||||
"string-similarity": "^1.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"react-inlinesvg": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-inlinesvg/-/react-inlinesvg-1.2.0.tgz",
|
||||
"integrity": "sha512-IsznU+UzpUwDGzBWbf0bfSRA5Jbqz87xeoqLM/nSIDPkoHksInF1wCGybTSn4sIui+30TqboRQP1wAelNTkdog==",
|
||||
"requires": {
|
||||
"exenv": "^1.2.2",
|
||||
"react-from-dom": "^0.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@samverschueren/stream-to-observable": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz",
|
||||
|
@ -3793,6 +3818,14 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-inlinesvg": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-inlinesvg/-/react-inlinesvg-0.8.1.tgz",
|
||||
"integrity": "sha512-pONmeCNqot4diXLhxb+jajDWX57rH/JmMu9H4NQWNMl5WUHAHmcrOfDfB05IgYBfRUX1Cvyjl9EZzKHxSxZpAA==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.2.tgz",
|
||||
|
@ -6533,6 +6566,11 @@
|
|||
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
|
||||
"dev": true
|
||||
},
|
||||
"bail": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
|
||||
"integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ=="
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
|
@ -7147,20 +7185,17 @@
|
|||
"character-entities": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.3.tgz",
|
||||
"integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w=="
|
||||
},
|
||||
"character-entities-legacy": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.3.tgz",
|
||||
"integrity": "sha512-YAxUpPoPwxYFsslbdKkhrGnXAtXoHNgYjlBM3WMXkWGTl5RsY3QmOyhwAgL8Nxm9l5LBThXGawxKPn68y6/fww==",
|
||||
"dev": true
|
||||
"integrity": "sha512-YAxUpPoPwxYFsslbdKkhrGnXAtXoHNgYjlBM3WMXkWGTl5RsY3QmOyhwAgL8Nxm9l5LBThXGawxKPn68y6/fww=="
|
||||
},
|
||||
"character-reference-invalid": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.3.tgz",
|
||||
"integrity": "sha512-VOq6PRzQBam/8Jm6XBGk2fNEnHXAdGd6go0rtd4weAGECBamHDwwCQSOT12TACIYUZegUXnV6xBXqUssijtxIg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-VOq6PRzQBam/8Jm6XBGk2fNEnHXAdGd6go0rtd4weAGECBamHDwwCQSOT12TACIYUZegUXnV6xBXqUssijtxIg=="
|
||||
},
|
||||
"chardet": {
|
||||
"version": "0.7.0",
|
||||
|
@ -7529,6 +7564,11 @@
|
|||
"urlgrey": "0.4.4"
|
||||
}
|
||||
},
|
||||
"collapse-white-space": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
|
||||
"integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ=="
|
||||
},
|
||||
"collection-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||
|
@ -8791,7 +8831,6 @@
|
|||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz",
|
||||
"integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"entities": "^2.0.0"
|
||||
|
@ -8800,14 +8839,12 @@
|
|||
"domelementtype": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
|
||||
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
|
||||
},
|
||||
"entities": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
|
||||
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -10098,6 +10135,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"exenv": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
|
||||
"integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
|
||||
},
|
||||
"exit": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
|
||||
|
@ -10321,8 +10363,7 @@
|
|||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"extend-shallow": {
|
||||
"version": "3.0.2",
|
||||
|
@ -12270,6 +12311,63 @@
|
|||
"uglify-js": "^3.5.1"
|
||||
}
|
||||
},
|
||||
"html-to-react": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.4.3.tgz",
|
||||
"integrity": "sha512-txe09A3vxW8yEZGJXJ1is5gGDfBEVACmZDSgwDyH5EsfRdOubBwBCg63ZThZP0xBn0UE4FyvMXZXmohusCxDcg==",
|
||||
"requires": {
|
||||
"domhandler": "^3.0",
|
||||
"htmlparser2": "^4.1.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"ramda": "^0.27"
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
|
||||
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
|
||||
"integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.1.0.tgz",
|
||||
"integrity": "sha512-CD9M0Dm1iaHfQ1R/TI+z3/JWp/pgub0j4jIQKH89ARR4ATAV2nbaOQS5XxU9maJP5jHaPdDDQSEHuE2UmpUTKg==",
|
||||
"requires": {
|
||||
"dom-serializer": "^0.2.1",
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.2.tgz",
|
||||
"integrity": "sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw=="
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
|
||||
"integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^3.0.0",
|
||||
"domutils": "^2.0.0",
|
||||
"entities": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.0.tgz",
|
||||
"integrity": "sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"html-webpack-plugin": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
|
||||
|
@ -12896,14 +12994,12 @@
|
|||
"is-alphabetical": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.3.tgz",
|
||||
"integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA=="
|
||||
},
|
||||
"is-alphanumerical": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.3.tgz",
|
||||
"integrity": "sha512-A1IGAPO5AW9vSh7omxIlOGwIqEvpW/TA+DksVOPM5ODuxKlZS09+TEM1E3275lJqO2oJ38vDpeAL3DCIiHE6eA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-alphabetical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0"
|
||||
|
@ -12938,8 +13034,7 @@
|
|||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.1.4",
|
||||
|
@ -12983,8 +13078,7 @@
|
|||
"is-decimal": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.3.tgz",
|
||||
"integrity": "sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-bvLSwoDg2q6Gf+E2LEPiklHZxxiSi3XAh4Mav65mKqTfCO1HM3uBs24TjEH8iJX3bbDdLXKJXBTmGzuTUuAEjQ=="
|
||||
},
|
||||
"is-descriptor": {
|
||||
"version": "0.1.6",
|
||||
|
@ -13075,8 +13169,7 @@
|
|||
"is-hexadecimal": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.3.tgz",
|
||||
"integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-zxQ9//Q3D/34poZf8fiy3m3XVpbQc7ren15iKqrTtLPwkPD/t3Scy9Imp63FujULGxuK0ZlCwoo5xNpktFgbOA=="
|
||||
},
|
||||
"is-in-browser": {
|
||||
"version": "1.1.3",
|
||||
|
@ -13156,8 +13249,7 @@
|
|||
"is-plain-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
|
||||
},
|
||||
"is-plain-object": {
|
||||
"version": "2.0.4",
|
||||
|
@ -13260,12 +13352,22 @@
|
|||
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-whitespace-character": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
|
||||
"integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w=="
|
||||
},
|
||||
"is-windows": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
|
||||
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
|
||||
"dev": true
|
||||
},
|
||||
"is-word-character": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
|
||||
"integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA=="
|
||||
},
|
||||
"is-wsl": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
|
||||
|
@ -14861,6 +14963,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
|
||||
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
|
||||
},
|
||||
"lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
|
||||
},
|
||||
"lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
|
@ -14872,11 +14979,20 @@
|
|||
"integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.every": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.every/-/lodash.every-4.6.0.tgz",
|
||||
"integrity": "sha1-64mYS+vENkJ5uzrvu9HKGb+mxqc="
|
||||
},
|
||||
"lodash.flattendeep": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
|
||||
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI="
|
||||
},
|
||||
"lodash.foreach": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
|
||||
"integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
|
||||
},
|
||||
"lodash.get": {
|
||||
"version": "4.4.2",
|
||||
|
@ -14893,6 +15009,16 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
|
||||
},
|
||||
"lodash.map": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
|
||||
"integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
|
||||
},
|
||||
"lodash.maxby": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.maxby/-/lodash.maxby-4.6.0.tgz",
|
||||
"integrity": "sha1-CCJABo88eiJ6oAqDgOTzjPB4bj0="
|
||||
},
|
||||
"lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
|
@ -15131,6 +15257,11 @@
|
|||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"markdown-escapes": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
|
||||
"integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg=="
|
||||
},
|
||||
"markdown-to-jsx": {
|
||||
"version": "6.11.4",
|
||||
"resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz",
|
||||
|
@ -15158,6 +15289,14 @@
|
|||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"mdast-add-list-metadata": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz",
|
||||
"integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==",
|
||||
"requires": {
|
||||
"unist-util-visit-parents": "1.1.2"
|
||||
}
|
||||
},
|
||||
"mdn-data": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
|
||||
|
@ -16192,7 +16331,6 @@
|
|||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
|
||||
"integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"character-entities": "^1.0.0",
|
||||
"character-entities-legacy": "^1.0.0",
|
||||
|
@ -17356,6 +17494,11 @@
|
|||
"react-clientside-effect": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"react-from-dom": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-from-dom/-/react-from-dom-0.3.1.tgz",
|
||||
"integrity": "sha512-PeNBa8iuzoD7qHA9O7YpGnXFvC+XFFwStmFh2/r2zJAvEIaRg6EwOj+EPcDIFwyYBhqPIItxIx/dGdeWiFivjQ=="
|
||||
},
|
||||
"react-gtm-module": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/react-gtm-module/-/react-gtm-module-2.0.8.tgz",
|
||||
|
@ -17495,6 +17638,28 @@
|
|||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-markdown": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-4.3.1.tgz",
|
||||
"integrity": "sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw==",
|
||||
"requires": {
|
||||
"html-to-react": "^1.3.4",
|
||||
"mdast-add-list-metadata": "1.0.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.8.6",
|
||||
"remark-parse": "^5.0.0",
|
||||
"unified": "^6.1.5",
|
||||
"unist-util-visit": "^1.3.0",
|
||||
"xtend": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-moment": {
|
||||
"version": "0.9.7",
|
||||
"resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.9.7.tgz",
|
||||
|
@ -18043,6 +18208,35 @@
|
|||
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
|
||||
"dev": true
|
||||
},
|
||||
"remark-parse": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz",
|
||||
"integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==",
|
||||
"requires": {
|
||||
"collapse-white-space": "^1.0.2",
|
||||
"is-alphabetical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0",
|
||||
"is-whitespace-character": "^1.0.0",
|
||||
"is-word-character": "^1.0.0",
|
||||
"markdown-escapes": "^1.0.0",
|
||||
"parse-entities": "^1.1.0",
|
||||
"repeat-string": "^1.5.4",
|
||||
"state-toggle": "^1.0.0",
|
||||
"trim": "0.0.1",
|
||||
"trim-trailing-lines": "^1.0.0",
|
||||
"unherit": "^1.0.4",
|
||||
"unist-util-remove-position": "^1.0.0",
|
||||
"vfile-location": "^2.0.0",
|
||||
"xtend": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"remove-trailing-separator": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
|
||||
|
@ -18088,8 +18282,7 @@
|
|||
"repeat-string": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
||||
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
|
||||
},
|
||||
"repeating": {
|
||||
"version": "2.0.1",
|
||||
|
@ -18100,6 +18293,11 @@
|
|||
"is-finite": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"replace-ext": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
|
||||
"integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs="
|
||||
},
|
||||
"request": {
|
||||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
|
@ -19308,6 +19506,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"state-toggle": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
|
||||
"integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ=="
|
||||
},
|
||||
"static-extend": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
|
||||
|
@ -19451,6 +19654,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"string-similarity": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-1.2.2.tgz",
|
||||
"integrity": "sha512-IoHUjcw3Srl8nsPlW04U3qwWPk3oG2ffLM0tN853d/E/JlIvcmZmDY2Kz5HzKp4lEi2T7QD7Zuvjq/1rDw+XcQ==",
|
||||
"requires": {
|
||||
"lodash.every": "^4.6.0",
|
||||
"lodash.flattendeep": "^4.4.0",
|
||||
"lodash.foreach": "^4.5.0",
|
||||
"lodash.map": "^4.6.0",
|
||||
"lodash.maxby": "^4.6.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
|
@ -20163,12 +20378,27 @@
|
|||
"resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz",
|
||||
"integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A=="
|
||||
},
|
||||
"trim": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
|
||||
"integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0="
|
||||
},
|
||||
"trim-right": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
|
||||
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
|
||||
"dev": true
|
||||
},
|
||||
"trim-trailing-lines": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
|
||||
"integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA=="
|
||||
},
|
||||
"trough": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
|
||||
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA=="
|
||||
},
|
||||
"ts-dedent": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-1.1.0.tgz",
|
||||
|
@ -20379,6 +20609,22 @@
|
|||
"integrity": "sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg==",
|
||||
"dev": true
|
||||
},
|
||||
"unherit": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
|
||||
"integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"unicode-canonical-property-names-ecmascript": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
|
||||
|
@ -20407,6 +20653,19 @@
|
|||
"integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
|
||||
"dev": true
|
||||
},
|
||||
"unified": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz",
|
||||
"integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==",
|
||||
"requires": {
|
||||
"bail": "^1.0.0",
|
||||
"extend": "^3.0.0",
|
||||
"is-plain-obj": "^1.1.0",
|
||||
"trough": "^1.0.0",
|
||||
"vfile": "^2.0.0",
|
||||
"x-is-string": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"union-class-names": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/union-class-names/-/union-class-names-1.0.0.tgz",
|
||||
|
@ -20448,6 +20707,47 @@
|
|||
"imurmurhash": "^0.1.4"
|
||||
}
|
||||
},
|
||||
"unist-util-is": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
|
||||
"integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A=="
|
||||
},
|
||||
"unist-util-remove-position": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
|
||||
"integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
|
||||
"requires": {
|
||||
"unist-util-visit": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"unist-util-stringify-position": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
|
||||
"integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ=="
|
||||
},
|
||||
"unist-util-visit": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
|
||||
"integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
|
||||
"requires": {
|
||||
"unist-util-visit-parents": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"unist-util-visit-parents": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
|
||||
"integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
|
||||
"requires": {
|
||||
"unist-util-is": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"unist-util-visit-parents": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz",
|
||||
"integrity": "sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q=="
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
|
@ -20740,6 +21040,30 @@
|
|||
"extsprintf": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"vfile": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
|
||||
"integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.4",
|
||||
"replace-ext": "1.0.0",
|
||||
"unist-util-stringify-position": "^1.0.0",
|
||||
"vfile-message": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"vfile-location": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
|
||||
"integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA=="
|
||||
},
|
||||
"vfile-message": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
|
||||
"integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
|
||||
"requires": {
|
||||
"unist-util-stringify-position": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"vm-browserify": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
||||
|
@ -21544,6 +21868,11 @@
|
|||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"x-is-string": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
|
||||
"integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI="
|
||||
},
|
||||
"xml-name-validator": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"@material-ui/core": "^4.5.1",
|
||||
"@material-ui/icons": "^4.5.1",
|
||||
"@material-ui/styles": "^4.5.2",
|
||||
"@saleor/macaw-ui": "^0.1.1-9",
|
||||
"apollo": "^2.21.2",
|
||||
"apollo-cache-inmemory": "^1.6.5",
|
||||
"apollo-client": "^2.6.8",
|
||||
|
@ -58,6 +59,7 @@
|
|||
"react-inlinesvg": "^0.8.4",
|
||||
"react-intl": "^3.1.8",
|
||||
"react-jss": "^10.0.0",
|
||||
"react-markdown": "^4.3.1",
|
||||
"react-moment": "^0.9.7",
|
||||
"react-router": "^5.0.1",
|
||||
"react-router-dom": "^5.0.1",
|
||||
|
@ -166,7 +168,7 @@
|
|||
"moduleNameMapper": {
|
||||
"@assets(.*)$": "<rootDir>/assets/$1",
|
||||
"@locale(.*)$": "<rootDir>/locale/$1",
|
||||
"@saleor(.*)$": "<rootDir>/src/$1",
|
||||
"@saleor(?!.*macaw)(.*)$": "<rootDir>/src/$1",
|
||||
"@test/(.*)$": "<rootDir>/testUtils/$1",
|
||||
"^lodash-es(.*)$": "lodash/$1"
|
||||
}
|
||||
|
|
2666
schema.graphql
|
@ -0,0 +1,18 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import AppActivateDialog, { AppActivateDialogProps } from "./AppActivateDialog";
|
||||
|
||||
const props: AppActivateDialogProps = {
|
||||
confirmButtonState: "default",
|
||||
name: "App",
|
||||
onClose: () => undefined,
|
||||
onConfirm: () => undefined,
|
||||
open: true
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / Activate app", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppActivateDialog {...props} />)
|
||||
.add("unnamed app", () => <AppActivateDialog {...props} name={null} />);
|
61
src/apps/components/AppActivateDialog/AppActivateDialog.tsx
Normal file
|
@ -0,0 +1,61 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import { getStringOrPlaceholder } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface AppActivateDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
open: boolean;
|
||||
name: string;
|
||||
onClose: () => void;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
const AppActivateDialog: React.FC<AppActivateDialogProps> = ({
|
||||
confirmButtonState,
|
||||
open,
|
||||
name,
|
||||
onClose,
|
||||
onConfirm
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
confirmButtonLabel={intl.formatMessage({
|
||||
defaultMessage: "Activate",
|
||||
description: "button label"
|
||||
})}
|
||||
confirmButtonState={confirmButtonState}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
onConfirm={onConfirm}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Activate App",
|
||||
description: "dialog header"
|
||||
})}
|
||||
variant="default"
|
||||
>
|
||||
<DialogContentText>
|
||||
{["", null].includes(name) ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to activate this app? Activating will start gathering events"
|
||||
description="activate app"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to activate {name}? Activating will start gathering events."
|
||||
description="activate app"
|
||||
values={{
|
||||
name: <strong>{getStringOrPlaceholder(name)}</strong>
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
AppActivateDialog.displayName = "AppActivateDialog";
|
||||
export default AppActivateDialog;
|
2
src/apps/components/AppActivateDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppActivateDialog";
|
||||
export { default } from "./AppActivateDialog";
|
|
@ -0,0 +1,20 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import AppDeactivateDialog, {
|
||||
AppDeactivateDialogProps
|
||||
} from "./AppDeactivateDialog";
|
||||
|
||||
const props: AppDeactivateDialogProps = {
|
||||
confirmButtonState: "default",
|
||||
name: "App",
|
||||
onClose: () => undefined,
|
||||
onConfirm: () => undefined,
|
||||
open: true
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / Deactivate app", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppDeactivateDialog {...props} />)
|
||||
.add("unnamed app", () => <AppDeactivateDialog {...props} name={null} />);
|
|
@ -0,0 +1,61 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import { getStringOrPlaceholder } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface AppDeactivateDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
open: boolean;
|
||||
name: string;
|
||||
onClose: () => void;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
const AppDeactivateDialog: React.FC<AppDeactivateDialogProps> = ({
|
||||
confirmButtonState,
|
||||
open,
|
||||
name,
|
||||
onClose,
|
||||
onConfirm
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
confirmButtonLabel={intl.formatMessage({
|
||||
defaultMessage: "Deactivate",
|
||||
description: "button label"
|
||||
})}
|
||||
confirmButtonState={confirmButtonState}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
onConfirm={onConfirm}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Dectivate App",
|
||||
description: "dialog header"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText>
|
||||
{["", null].includes(name) ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to disable this app? Your data will be kept until you reactivate the app. You will be still billed for the app."
|
||||
description="deactivate app"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to disable {name}? Your data will be kept until you reactivate the app. You will be still billed for the app."
|
||||
description="deactivate app"
|
||||
values={{
|
||||
name: <strong>{getStringOrPlaceholder(name)}</strong>
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
AppDeactivateDialog.displayName = "AppDeactivateDialog";
|
||||
export default AppDeactivateDialog;
|
2
src/apps/components/AppDeactivateDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppDeactivateDialog";
|
||||
export { default } from "./AppDeactivateDialog";
|
|
@ -0,0 +1,19 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import AppDeleteDialog, { AppDeleteDialogProps } from "./AppDeleteDialog";
|
||||
|
||||
const props: AppDeleteDialogProps = {
|
||||
confirmButtonState: "default",
|
||||
name: "App",
|
||||
onClose: () => undefined,
|
||||
onConfirm: () => undefined,
|
||||
open: true,
|
||||
type: "EXTERNAL"
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / Delete app", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppDeleteDialog {...props} />)
|
||||
.add("unnamed app", () => <AppDeleteDialog {...props} name={null} />);
|
67
src/apps/components/AppDeleteDialog/AppDeleteDialog.tsx
Normal file
|
@ -0,0 +1,67 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import { getStringOrPlaceholder } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface AppDeleteDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
open: boolean;
|
||||
name: string;
|
||||
onClose: () => void;
|
||||
onConfirm: () => void;
|
||||
type: "CUSTOM" | "EXTERNAL";
|
||||
}
|
||||
|
||||
const AppDeleteDialog: React.FC<AppDeleteDialogProps> = ({
|
||||
confirmButtonState,
|
||||
open,
|
||||
name,
|
||||
onClose,
|
||||
onConfirm,
|
||||
type
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
confirmButtonState={confirmButtonState}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
onConfirm={onConfirm}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete App",
|
||||
description: "dialog header"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText>
|
||||
{["", null].includes(name) ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete this app?"
|
||||
description="delete app"
|
||||
/>
|
||||
) : type === "EXTERNAL" ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Deleting {name}, you will remove installation of the app. If you are paying for app subscription, remember to unsubscribe from the app in Saleor Marketplace. Are you sure you want to delete the app?"
|
||||
description="delete app"
|
||||
values={{
|
||||
name: <strong>{getStringOrPlaceholder(name)}</strong>
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Deleting {name}, you will delete all the data and webhooks regarding this app. Are you sure you want to do that?"
|
||||
description="delete custom app"
|
||||
values={{
|
||||
name: <strong>{getStringOrPlaceholder(name)}</strong>
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
AppDeleteDialog.displayName = "AppDeleteDialog";
|
||||
export default AppDeleteDialog;
|
2
src/apps/components/AppDeleteDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppDeleteDialog";
|
||||
export { default } from "./AppDeleteDialog";
|
|
@ -0,0 +1,20 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import { appDetails } from "../../fixtures";
|
||||
import AppDetailsPage, { AppDetailsPageProps } from "./AppDetailsPage";
|
||||
|
||||
const props: AppDetailsPageProps = {
|
||||
data: appDetails,
|
||||
loading: false,
|
||||
navigateToAppSettings: () => undefined,
|
||||
onAppActivateOpen: () => undefined,
|
||||
onAppDeactivateOpen: () => undefined,
|
||||
onBack: () => undefined
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / App details", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppDetailsPage {...props} />)
|
||||
.add("loading", () => <AppDetailsPage {...props} loading={true} />);
|
195
src/apps/components/AppDetailsPage/AppDetailsPage.tsx
Normal file
|
@ -0,0 +1,195 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Container from "@saleor/components/Container";
|
||||
import ExternalLink from "@saleor/components/ExternalLink";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
||||
import activateIcon from "../../../../assets/images/activate-icon.svg";
|
||||
import settingsIcon from "../../../../assets/images/settings-icon.svg";
|
||||
import supportIcon from "../../../../assets/images/support-icon.svg";
|
||||
import { useStyles } from "../../styles";
|
||||
import { App_app } from "../../types/App";
|
||||
import DeactivatedText from "../DeactivatedText";
|
||||
|
||||
export interface AppDetailsPageProps {
|
||||
loading: boolean;
|
||||
data: App_app;
|
||||
navigateToAppSettings: () => void;
|
||||
onAppActivateOpen: () => void;
|
||||
onAppDeactivateOpen: () => void;
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
|
||||
data,
|
||||
loading,
|
||||
navigateToAppSettings,
|
||||
onAppActivateOpen,
|
||||
onAppDeactivateOpen,
|
||||
onBack
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.apps)}
|
||||
</AppHeader>
|
||||
<PageHeader
|
||||
title={
|
||||
<>
|
||||
{data?.name} {!data?.isActive && <DeactivatedText />}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
href={data?.homepageUrl}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
data-tc="open-app"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage defaultMessage="Open App" description="button" />
|
||||
</Button>
|
||||
</PageHeader>
|
||||
<div className={classes.appHeader}>
|
||||
{data ? (
|
||||
<div className={classes.appHeaderLinks}>
|
||||
<ExternalLink
|
||||
className={classes.headerLinkContainer}
|
||||
href={data.supportUrl}
|
||||
target="_blank"
|
||||
>
|
||||
<img src={supportIcon} alt="" />
|
||||
<FormattedMessage
|
||||
defaultMessage="Get Support"
|
||||
description="link"
|
||||
/>
|
||||
</ExternalLink>
|
||||
<Button
|
||||
color="primary"
|
||||
className={classes.headerLinkContainer}
|
||||
onClick={navigateToAppSettings}
|
||||
>
|
||||
<img src={settingsIcon} alt="" />
|
||||
|
||||
<FormattedMessage
|
||||
defaultMessage="Edit settings"
|
||||
description="link"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="text"
|
||||
color="primary"
|
||||
className={classes.headerLinkContainer}
|
||||
disableFocusRipple
|
||||
onClick={data.isActive ? onAppDeactivateOpen : onAppActivateOpen}
|
||||
>
|
||||
<img src={activateIcon} alt="" />
|
||||
{data?.isActive ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Deactivate"
|
||||
description="link"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Activate"
|
||||
description="link"
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Skeleton />
|
||||
)}
|
||||
<div className={classes.hr} />
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "About this app",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{!loading ? <ReactMarkdown source={data?.aboutApp} /> : <Skeleton />}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CardSpacer />
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "App permissions",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{!loading ? (
|
||||
<>
|
||||
<Typography>
|
||||
<FormattedMessage
|
||||
defaultMessage="This app has permissions to:"
|
||||
description="apps about permissions"
|
||||
/>
|
||||
</Typography>
|
||||
{!!data?.permissions?.length && (
|
||||
<ul className={classes.permissionsContainer}>
|
||||
{data?.permissions?.map(perm => (
|
||||
<li key={perm.code}>{perm.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Skeleton />
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CardSpacer />
|
||||
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Data privacy",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{!loading ? (
|
||||
<>
|
||||
<Typography>{data?.dataPrivacy}</Typography>
|
||||
<ExternalLink
|
||||
className={classes.linkContainer}
|
||||
href={data?.dataPrivacyUrl}
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="View this app’s privacy policy"
|
||||
description="app privacy policy link"
|
||||
/>
|
||||
</ExternalLink>
|
||||
</>
|
||||
) : (
|
||||
<Skeleton />
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CardSpacer />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
AppDetailsPage.displayName = "AppDetailsPage";
|
||||
export default AppDetailsPage;
|
2
src/apps/components/AppDetailsPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppDetailsPage";
|
||||
export { default } from "./AppDetailsPage";
|
|
@ -0,0 +1,20 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import { appDetails } from "../../fixtures";
|
||||
import AppDetailsSettingsPage, {
|
||||
AppDetailsSettingsPageProps
|
||||
} from "./AppDetailsSettingsPage";
|
||||
|
||||
const props: AppDetailsSettingsPageProps = {
|
||||
backendHost: "host",
|
||||
data: appDetails,
|
||||
navigateToDashboard: () => undefined,
|
||||
onBack: () => undefined,
|
||||
onError: () => undefined
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / App details settings", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppDetailsSettingsPage {...props} />);
|
|
@ -0,0 +1,146 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Container from "@saleor/components/Container";
|
||||
import Grid from "@saleor/components/Grid";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import useTheme from "@saleor/hooks/useTheme";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import classNames from "classnames";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import urlJoin from "url-join";
|
||||
|
||||
import { App_app } from "../../types/App";
|
||||
import { useStyles } from "./styles";
|
||||
import useSettingsBreadcrumbs from "./useSettingsBreadcrumbs";
|
||||
|
||||
export interface AppDetailsSettingsPageProps {
|
||||
backendHost: string;
|
||||
data: App_app;
|
||||
navigateToDashboard: () => void;
|
||||
onBack: () => void;
|
||||
onError: () => void;
|
||||
}
|
||||
|
||||
export const AppDetailsSettingsPage: React.FC<AppDetailsSettingsPageProps> = ({
|
||||
backendHost,
|
||||
data,
|
||||
navigateToDashboard,
|
||||
onBack,
|
||||
onError
|
||||
}) => {
|
||||
const iframeRef = useRef(null);
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
const { sendThemeToExtension } = useTheme();
|
||||
const [breadcrumbs, onBreadcrumbClick] = useSettingsBreadcrumbs();
|
||||
|
||||
useEffect(() => {
|
||||
if (!iframeRef.current?.innerHTML && data?.configurationUrl) {
|
||||
fetch(data?.configurationUrl, {
|
||||
headers: {
|
||||
"x-saleor-domain": backendHost,
|
||||
"x-saleor-token": data.accessToken
|
||||
},
|
||||
method: "GET"
|
||||
})
|
||||
.then(async response => {
|
||||
const url = new URL(response.url);
|
||||
const text = await response.text();
|
||||
const content = new DOMParser().parseFromString(text, "text/html");
|
||||
|
||||
const iFrame = document.createElement("iframe");
|
||||
iFrame.src = "about:blank";
|
||||
iFrame.id = "extension-app";
|
||||
iframeRef.current.innerHTML = "";
|
||||
iframeRef.current.appendChild(iFrame);
|
||||
const iFrameDoc =
|
||||
iFrame.contentWindow && iFrame.contentWindow.document;
|
||||
|
||||
const documentElement = content.documentElement;
|
||||
const formScript = documentElement.querySelector("script");
|
||||
const formURL = new URL(documentElement.querySelector("script").src);
|
||||
formScript.src = `${urlJoin(url.origin, formURL.pathname)}`;
|
||||
iFrameDoc.write(content.documentElement.innerHTML);
|
||||
iFrameDoc.close();
|
||||
iFrame.contentWindow.onload = sendThemeToExtension;
|
||||
})
|
||||
.catch(() => onError());
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.apps)}
|
||||
</AppHeader>
|
||||
<Grid variant="uniform">
|
||||
<div className={classes.breadcrumbContainer}>
|
||||
<div className={classes.breadcrumbs}>
|
||||
<Typography
|
||||
className={classNames(
|
||||
classes.breadcrumb,
|
||||
classes.breadcrumbDisabled
|
||||
)}
|
||||
variant="h5"
|
||||
>
|
||||
{data?.name}
|
||||
</Typography>
|
||||
{breadcrumbs.map(b => (
|
||||
<Typography
|
||||
className={classes.breadcrumb}
|
||||
variant="h5"
|
||||
onClick={() => onBreadcrumbClick(b.value)}
|
||||
key={b.label}
|
||||
>
|
||||
{b.label}
|
||||
</Typography>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.appSettingsHeader}>
|
||||
<Button
|
||||
onClick={navigateToDashboard}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
>
|
||||
<FormattedMessage defaultMessage="Dashboard" description="button" />
|
||||
</Button>
|
||||
<Button
|
||||
href={data?.homepageUrl}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
data-tc="open-app"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage defaultMessage="My App" description="button" />
|
||||
</Button>
|
||||
<Button
|
||||
href={data?.supportUrl}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
data-tc="open-support"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Support/FAQ"
|
||||
description="button"
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</Grid>
|
||||
<CardSpacer />
|
||||
|
||||
<Hr />
|
||||
|
||||
<CardSpacer />
|
||||
<div ref={iframeRef} className={classes.iframeContainer} />
|
||||
<CardSpacer />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
AppDetailsSettingsPage.displayName = "AppDetailsSettingsPage";
|
||||
export default AppDetailsSettingsPage;
|
2
src/apps/components/AppDetailsSettingsPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppDetailsSettingsPage";
|
||||
export { default } from "./AppDetailsSettingsPage";
|
62
src/apps/components/AppDetailsSettingsPage/styles.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
appSettingsHeader: {
|
||||
"& > button, & > a": {
|
||||
"&:last-child": {
|
||||
marginRight: 0
|
||||
},
|
||||
marginRight: theme.spacing(2)
|
||||
},
|
||||
display: "flex",
|
||||
justifyContent: "flex-end"
|
||||
},
|
||||
breadcrumb: {
|
||||
"&:not(:last-child)": {
|
||||
"&:after": {
|
||||
content: "'/'",
|
||||
display: "block",
|
||||
position: "absolute",
|
||||
right: -theme.spacing(2),
|
||||
top: 0
|
||||
},
|
||||
"&:not(:first-child):hover": {
|
||||
cursor: "pointer",
|
||||
textDecoration: "underline"
|
||||
}
|
||||
},
|
||||
marginRight: theme.spacing(3),
|
||||
position: "relative"
|
||||
},
|
||||
breadcrumbContainer: {
|
||||
alignItems: "center",
|
||||
display: "flex"
|
||||
},
|
||||
breadcrumbDisabled: {
|
||||
"&:hover": {
|
||||
textDecoration: "none"
|
||||
},
|
||||
color: theme.palette.text.disabled
|
||||
},
|
||||
breadcrumbs: {
|
||||
display: "flex"
|
||||
},
|
||||
hr: {
|
||||
border: "none",
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
height: 0,
|
||||
marginBottom: 0,
|
||||
marginTop: 0,
|
||||
width: "100%"
|
||||
},
|
||||
iframeContainer: {
|
||||
"& > iframe": {
|
||||
border: "none",
|
||||
minHeight: "75vh",
|
||||
width: "100%"
|
||||
}
|
||||
}
|
||||
}),
|
||||
{ name: "AppDetailsSettingsPage" }
|
||||
);
|
|
@ -0,0 +1,38 @@
|
|||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbChangeMessage,
|
||||
BreadcrumbClickMessage,
|
||||
ExtensionMessageEvent,
|
||||
ExtensionMessageType,
|
||||
sendMessageToExtension,
|
||||
useExtensionMessage
|
||||
} from "@saleor/macaw-ui/extensions";
|
||||
import { useState } from "react";
|
||||
|
||||
type UseSettingsBreadcrumbs = [Breadcrumb[], (value: string) => void];
|
||||
function useSettingsBreadcrumbs(): UseSettingsBreadcrumbs {
|
||||
const [breadcrumbs, setBreadcrumbs] = useState<Breadcrumb[]>([]);
|
||||
|
||||
const handleBreadcrumbSet = (
|
||||
event: ExtensionMessageEvent<BreadcrumbChangeMessage>
|
||||
) => {
|
||||
if (event.data.type === ExtensionMessageType.BREADCRUMB_SET) {
|
||||
setBreadcrumbs(event.data.breadcrumbs);
|
||||
}
|
||||
};
|
||||
|
||||
useExtensionMessage(handleBreadcrumbSet);
|
||||
|
||||
const handleBreadcrumbClick = (value: string) =>
|
||||
sendMessageToExtension<BreadcrumbClickMessage>(
|
||||
{
|
||||
breadcrumb: value,
|
||||
type: ExtensionMessageType.BREADCRUMB_CLICK
|
||||
},
|
||||
"*"
|
||||
);
|
||||
|
||||
return [breadcrumbs, handleBreadcrumbClick];
|
||||
}
|
||||
|
||||
export default useSettingsBreadcrumbs;
|
|
@ -0,0 +1,22 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import AppInProgressDeleteDialog, {
|
||||
AppInProgressDeleteDialogProps
|
||||
} from "./AppInProgressDeleteDialog";
|
||||
|
||||
const props: AppInProgressDeleteDialogProps = {
|
||||
confirmButtonState: "default",
|
||||
name: "App",
|
||||
onClose: () => undefined,
|
||||
onConfirm: () => undefined,
|
||||
open: true
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / Delete app failed installation", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppInProgressDeleteDialog {...props} />)
|
||||
.add("unnamed app", () => (
|
||||
<AppInProgressDeleteDialog {...props} name={null} />
|
||||
));
|
|
@ -0,0 +1,57 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import { getStringOrPlaceholder } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface AppInProgressDeleteDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
open: boolean;
|
||||
name: string;
|
||||
onClose: () => void;
|
||||
onConfirm: () => void;
|
||||
}
|
||||
|
||||
const AppInProgressDeleteDialog: React.FC<AppInProgressDeleteDialogProps> = ({
|
||||
confirmButtonState,
|
||||
open,
|
||||
name,
|
||||
onClose,
|
||||
onConfirm
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<ActionDialog
|
||||
confirmButtonState={confirmButtonState}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
onConfirm={onConfirm}
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete App",
|
||||
description: "dialog header"
|
||||
})}
|
||||
variant="delete"
|
||||
>
|
||||
<DialogContentText>
|
||||
{["", null].includes(name) ? (
|
||||
<FormattedMessage
|
||||
defaultMessage="Are you sure you want to delete this app?"
|
||||
description="delete app"
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
defaultMessage="Deleting {name}, you will remove installation of the app. If you are paying for app subscription, remember to unsubscribe from the app in Saleor Marketplace. Are you sure you want to delete the app?"
|
||||
description="delete app"
|
||||
values={{
|
||||
name: <strong>{getStringOrPlaceholder(name)}</strong>
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</DialogContentText>
|
||||
</ActionDialog>
|
||||
);
|
||||
};
|
||||
AppInProgressDeleteDialog.displayName = "AppInProgressDeleteDialog";
|
||||
export default AppInProgressDeleteDialog;
|
2
src/apps/components/AppInProgressDeleteDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppInProgressDeleteDialog";
|
||||
export { default } from "./AppInProgressDeleteDialog";
|
|
@ -0,0 +1,56 @@
|
|||
import errorImg from "@assets/images/app-install-error.svg";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Container from "@saleor/components/Container";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
interface AppInstallErrorPageProps {
|
||||
onBack: () => void;
|
||||
}
|
||||
|
||||
export const AppInstallErrorPage: React.FC<AppInstallErrorPageProps> = ({
|
||||
onBack
|
||||
}) => {
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<Container className={classes.root}>
|
||||
<Grid spacing={3} alignItems="center" container>
|
||||
<Grid xs={12} sm={6} item>
|
||||
<img src={errorImg} alt="" />
|
||||
</Grid>
|
||||
<Grid xs={12} sm={6} item>
|
||||
<Typography variant="h3" component="h3">
|
||||
<FormattedMessage
|
||||
defaultMessage="There’s a problem with app."
|
||||
description="title"
|
||||
/>
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
<FormattedMessage
|
||||
defaultMessage="Saleor couldn’t fetch crucial information regarding installation. Without those System can’t install the app in your Saleor. Please use the button below to get back to system’s dashboard."
|
||||
description="content"
|
||||
/>
|
||||
</Typography>
|
||||
<Button
|
||||
className={classes.button}
|
||||
color="primary"
|
||||
variant="contained"
|
||||
onClick={onBack}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Back to homepage"
|
||||
description="button"
|
||||
/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppInstallErrorPage;
|
2
src/apps/components/AppInstallErrorPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppInstallErrorPage";
|
||||
export { default } from "./AppInstallErrorPage";
|
26
src/apps/components/AppInstallErrorPage/styles.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
button: {
|
||||
marginTop: theme.spacing(2),
|
||||
padding: theme.spacing(1.5, 2)
|
||||
},
|
||||
root: {
|
||||
"& > div": {
|
||||
minHeight: "80vh"
|
||||
},
|
||||
"& h3": {
|
||||
fontWeight: 600,
|
||||
marginBottom: theme.spacing(3),
|
||||
maxWidth: theme.spacing(60)
|
||||
},
|
||||
"& img": {
|
||||
maxWidth: "100%"
|
||||
}
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: "AppInstallErrorPage"
|
||||
}
|
||||
);
|
|
@ -0,0 +1,18 @@
|
|||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import { installApp } from "../../fixtures";
|
||||
import AppInstallPage, { AppInstallPageProps } from "./AppInstallPage";
|
||||
|
||||
const props: AppInstallPageProps = {
|
||||
data: installApp,
|
||||
loading: false,
|
||||
navigateToAppsList: () => undefined,
|
||||
onSubmit: () => undefined
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / Install App", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppInstallPage {...props} />)
|
||||
.add("loading", () => <AppInstallPage {...props} loading={true} />);
|
160
src/apps/components/AppInstallPage/AppInstallPage.tsx
Normal file
|
@ -0,0 +1,160 @@
|
|||
import saleorDarkLogoSmall from "@assets/images/logo-dark-small.svg";
|
||||
import plusIcon from "@assets/images/plus-icon.svg";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Container from "@saleor/components/Container";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import { buttonMessages } from "@saleor/intl";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { useStyles } from "../../styles";
|
||||
import { AppFetch_appFetchManifest_manifest } from "../../types/AppFetch";
|
||||
|
||||
export interface AppInstallPageProps {
|
||||
data: AppFetch_appFetchManifest_manifest;
|
||||
loading: boolean;
|
||||
navigateToAppsList: () => void;
|
||||
onSubmit: () => void;
|
||||
}
|
||||
|
||||
export const AppInstallPage: React.FC<AppInstallPageProps> = ({
|
||||
data,
|
||||
loading,
|
||||
navigateToAppsList,
|
||||
onSubmit
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
|
||||
const name = data?.name || "";
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<CardSpacer />
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={
|
||||
loading ? (
|
||||
<Skeleton />
|
||||
) : (
|
||||
intl.formatMessage(
|
||||
{
|
||||
defaultMessage: `You are about to install {name}`,
|
||||
description: "section header"
|
||||
},
|
||||
{ name }
|
||||
)
|
||||
)
|
||||
}
|
||||
/>
|
||||
<CardContent className={classes.installCard}>
|
||||
{loading ? (
|
||||
<Skeleton />
|
||||
) : (
|
||||
<div className={classes.installAppContainer}>
|
||||
<div
|
||||
className={classNames(
|
||||
classes.installIcon,
|
||||
classes.installSaleorIcon
|
||||
)}
|
||||
>
|
||||
<img src={saleorDarkLogoSmall} alt="" />
|
||||
</div>
|
||||
<img src={plusIcon} alt="" />
|
||||
<div className={classes.installIcon}>
|
||||
<h2>{name?.charAt(0).toUpperCase()}</h2>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CardSpacer />
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "App permissions",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{loading ? (
|
||||
<Skeleton />
|
||||
) : (
|
||||
<>
|
||||
<Typography className={classes.installPermissionTitle}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Installing this app will give it following permissions:"
|
||||
description="install app permissions"
|
||||
/>
|
||||
</Typography>
|
||||
{!!data?.permissions?.length && (
|
||||
<ul className={classes.permissionsContainer}>
|
||||
{data?.permissions?.map(perm => (
|
||||
<li key={perm.code}>{perm.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
<Hr className={classes.installSpacer} />
|
||||
|
||||
<Typography
|
||||
variant="body2"
|
||||
className={classes.installPrivacyText}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Uninstalling the app will remove all your customer’s personal data stored by {name}. "
|
||||
description="install app privacy"
|
||||
values={{ name }}
|
||||
/>
|
||||
<a
|
||||
href={data?.dataPrivacyUrl}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Learn more about data privacy"
|
||||
description="app data privacy link"
|
||||
/>
|
||||
</a>
|
||||
</Typography>
|
||||
</>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CardSpacer />
|
||||
<Grid container justify="space-between">
|
||||
<Grid xs={6} item>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
onClick={navigateToAppsList}
|
||||
>
|
||||
<Typography color="primary">
|
||||
<FormattedMessage {...buttonMessages.cancel} />
|
||||
</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
<Grid xs={6} item className={classes.alignRight}>
|
||||
<Button variant="contained" color="primary" onClick={onSubmit}>
|
||||
<Typography className={classes.installText}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Install App"
|
||||
description="install button"
|
||||
/>
|
||||
</Typography>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
AppInstallPage.displayName = "AppInstallPage";
|
||||
export default AppInstallPage;
|
2
src/apps/components/AppInstallPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppInstallPage";
|
||||
export { default } from "./AppInstallPage";
|
117
src/apps/components/AppsInProgress/AppsInProgress.tsx
Normal file
|
@ -0,0 +1,117 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Progress from "@material-ui/core/CircularProgress";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Tooltip from "@material-ui/core/Tooltip";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import ErrorIcon from "@material-ui/icons/Error";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import { renderCollection, stopPropagation } from "@saleor/misc";
|
||||
import classNames from "classnames";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { JobStatusEnum } from "../../../types/globalTypes";
|
||||
import { useStyles } from "../../styles";
|
||||
import { AppsInstallations_appsInstallations } from "../../types/AppsInstallations";
|
||||
import CardContainer from "../CardContainer";
|
||||
|
||||
export interface AppsInProgressProps {
|
||||
appsList: AppsInstallations_appsInstallations[];
|
||||
disabled: boolean;
|
||||
onAppInstallRetry: (id: string) => void;
|
||||
onRemove: (id: string) => void;
|
||||
}
|
||||
|
||||
const AppsInProgress: React.FC<AppsInProgressProps> = ({
|
||||
appsList,
|
||||
disabled,
|
||||
onAppInstallRetry,
|
||||
onRemove,
|
||||
...props
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
<CardContainer
|
||||
header={
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Ongoing Installations",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<TableBody>
|
||||
{renderCollection(appsList, ({ status, appName, id, message }) => (
|
||||
<TableRow key={id} className={classes.tableRow}>
|
||||
<TableCell className={classes.colName}>
|
||||
<span data-tc="name">{appName}</span>
|
||||
</TableCell>
|
||||
{status === JobStatusEnum.PENDING && (
|
||||
<TableCell
|
||||
className={classNames(
|
||||
classes.colAction,
|
||||
classes.colInstallAction
|
||||
)}
|
||||
>
|
||||
<Typography variant="body2" className={classes.text}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Installing app..."
|
||||
description="app installation"
|
||||
/>
|
||||
</Typography>
|
||||
<div className={classes.colSpinner}>
|
||||
<Progress size={20} />
|
||||
</div>
|
||||
</TableCell>
|
||||
)}
|
||||
{status === JobStatusEnum.FAILED && (
|
||||
<TableCell
|
||||
className={classNames(
|
||||
classes.colAction,
|
||||
classes.colInstallAction
|
||||
)}
|
||||
>
|
||||
<Typography variant="body2" className={classes.error}>
|
||||
<FormattedMessage
|
||||
defaultMessage="There was a problem during installation"
|
||||
description="app installation error"
|
||||
/>
|
||||
<Tooltip
|
||||
title={<Typography variant="body2">{message}</Typography>}
|
||||
classes={{
|
||||
tooltip: classes.customTooltip
|
||||
}}
|
||||
>
|
||||
<ErrorIcon />
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
<Button color="primary" onClick={() => onAppInstallRetry(id)}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Retry"
|
||||
description="retry installation"
|
||||
/>
|
||||
</Button>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={stopPropagation(() => onRemove(id))}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</CardContainer>
|
||||
);
|
||||
};
|
||||
|
||||
AppsInProgress.displayName = "AppsInProgress";
|
||||
export default AppsInProgress;
|
2
src/apps/components/AppsInProgress/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppsInProgress";
|
||||
export { default } from "./AppsInProgress";
|
58
src/apps/components/AppsListPage/AppListPage.stories.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
listActionsProps,
|
||||
pageListProps,
|
||||
searchPageProps,
|
||||
sortPageProps,
|
||||
tabPageProps
|
||||
} from "@saleor/fixtures";
|
||||
import Decorator from "@saleor/storybook/Decorator";
|
||||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import { appsInProgress, appsList, customAppsList } from "../../fixtures";
|
||||
import AppsListPage, { AppsListPageProps } from "./AppsListPage";
|
||||
|
||||
const props: AppsListPageProps = {
|
||||
...listActionsProps,
|
||||
...pageListProps.default,
|
||||
...searchPageProps,
|
||||
...sortPageProps,
|
||||
...tabPageProps,
|
||||
appsInProgressList: { appsInstallations: appsInProgress },
|
||||
customAppsList,
|
||||
disabled: false,
|
||||
installedAppsList: appsList,
|
||||
loadingAppsInProgress: false,
|
||||
navigateToCustomApp: () => undefined,
|
||||
navigateToCustomAppCreate: () => undefined,
|
||||
onAppInProgressRemove: () => undefined,
|
||||
onAppInstallRetry: () => undefined,
|
||||
onCustomAppRemove: () => undefined,
|
||||
onInstalledAppRemove: () => undefined,
|
||||
onNextPage: () => undefined,
|
||||
onPreviousPage: () => undefined,
|
||||
onRowClick: () => undefined,
|
||||
onSettingsRowClick: () => undefined
|
||||
};
|
||||
|
||||
storiesOf("Views / Apps / Apps list", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <AppsListPage {...props} />)
|
||||
.add("loading", () => (
|
||||
<AppsListPage
|
||||
{...props}
|
||||
appsInProgressList={undefined}
|
||||
disabled={true}
|
||||
loadingAppsInProgress={true}
|
||||
installedAppsList={undefined}
|
||||
customAppsList={undefined}
|
||||
/>
|
||||
))
|
||||
.add("no data", () => (
|
||||
<AppsListPage
|
||||
{...props}
|
||||
appsInProgressList={undefined}
|
||||
installedAppsList={[]}
|
||||
customAppsList={[]}
|
||||
/>
|
||||
));
|
76
src/apps/components/AppsListPage/AppsListPage.tsx
Normal file
|
@ -0,0 +1,76 @@
|
|||
import Container from "@saleor/components/Container";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { ListProps } from "@saleor/types";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { AppsInstallations } from "../../types/AppsInstallations";
|
||||
import { AppsList_apps_edges } from "../../types/AppsList";
|
||||
import AppsInProgress from "../AppsInProgress/AppsInProgress";
|
||||
import CustomApps from "../CustomApps/CustomApps";
|
||||
import InstalledApps from "../InstalledApps/InstalledApps";
|
||||
import Marketplace from "../Marketplace";
|
||||
|
||||
export interface AppsListPageProps extends ListProps {
|
||||
installedAppsList: AppsList_apps_edges[];
|
||||
customAppsList: AppsList_apps_edges[];
|
||||
appsInProgressList?: AppsInstallations;
|
||||
loadingAppsInProgress: boolean;
|
||||
navigateToCustomApp: (id: string) => () => void;
|
||||
navigateToCustomAppCreate: () => void;
|
||||
onInstalledAppRemove: (id: string) => void;
|
||||
onCustomAppRemove: (id: string) => void;
|
||||
onAppInProgressRemove: (id: string) => void;
|
||||
onAppInstallRetry: (id: string) => void;
|
||||
onSettingsRowClick: (id: string) => () => void;
|
||||
}
|
||||
|
||||
const AppsListPage: React.FC<AppsListPageProps> = ({
|
||||
appsInProgressList,
|
||||
customAppsList,
|
||||
installedAppsList,
|
||||
loadingAppsInProgress,
|
||||
navigateToCustomApp,
|
||||
navigateToCustomAppCreate,
|
||||
onInstalledAppRemove,
|
||||
onCustomAppRemove,
|
||||
onAppInProgressRemove,
|
||||
onAppInstallRetry,
|
||||
onSettingsRowClick,
|
||||
...listProps
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const appsInProgress = appsInProgressList?.appsInstallations;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<PageHeader title={intl.formatMessage(sectionNames.apps)} />
|
||||
{!!appsInProgress?.length && (
|
||||
<AppsInProgress
|
||||
appsList={appsInProgress}
|
||||
disabled={loadingAppsInProgress}
|
||||
onAppInstallRetry={onAppInstallRetry}
|
||||
onRemove={onAppInProgressRemove}
|
||||
/>
|
||||
)}
|
||||
<InstalledApps
|
||||
appsList={installedAppsList}
|
||||
onRemove={onInstalledAppRemove}
|
||||
onSettingsRowClick={onSettingsRowClick}
|
||||
{...listProps}
|
||||
/>
|
||||
<CustomApps
|
||||
appsList={customAppsList}
|
||||
navigateToCustomApp={navigateToCustomApp}
|
||||
navigateToCustomAppCreate={navigateToCustomAppCreate}
|
||||
onRemove={onCustomAppRemove}
|
||||
/>
|
||||
<Marketplace />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
AppsListPage.displayName = "AppsListPage";
|
||||
export default AppsListPage;
|
2
src/apps/components/AppsListPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppsListPage";
|
||||
export { default } from "./AppsListPage";
|
21
src/apps/components/AppsSkeleton/AppsSkeleton.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import React from "react";
|
||||
|
||||
import { useStyles } from "../../styles";
|
||||
|
||||
export const AppsSkeleton = () => {
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<TableRow className={classes.tableRow}>
|
||||
<TableCell className={classes.colName}>
|
||||
<Skeleton />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
};
|
||||
|
||||
AppsSkeleton.displayName = "AppsSkeleton";
|
||||
export default AppsSkeleton;
|
2
src/apps/components/AppsSkeleton/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppsSkeleton";
|
||||
export { default } from "./AppsSkeleton";
|
29
src/apps/components/CardContainer/CardContainer.tsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||
import React from "react";
|
||||
|
||||
import { useStyles } from "../../styles";
|
||||
|
||||
export interface CardContainerProps {
|
||||
children: React.ReactNode;
|
||||
header: React.ReactNode;
|
||||
}
|
||||
|
||||
const CardContainer: React.FC<CardContainerProps> = ({ children, header }) => {
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<div className={classes.appContainer}>
|
||||
<Card>
|
||||
{header}
|
||||
<CardContent className={classes.appContent}>
|
||||
<ResponsiveTable>{children}</ResponsiveTable>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
CardContainer.displayName = "CardContainer";
|
||||
export default CardContainer;
|
2
src/apps/components/CardContainer/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CardContainer";
|
||||
export { default } from "./CardContainer";
|
|
@ -1,6 +1,7 @@
|
|||
import { AppErrorFragment } from "@saleor/apps/types/AppErrorFragment";
|
||||
import AccountPermissions from "@saleor/components/AccountPermissions";
|
||||
import AccountStatus from "@saleor/components/AccountStatus";
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import AppStatus from "@saleor/components/AppStatus";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import Container from "@saleor/components/Container";
|
||||
|
@ -9,32 +10,31 @@ import Grid from "@saleor/components/Grid";
|
|||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo";
|
||||
import { AccountErrorFragment } from "@saleor/fragments/types/AccountErrorFragment";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { PermissionEnum } from "@saleor/types/globalTypes";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import getAccountErrorMessage from "@saleor/utils/errors/account";
|
||||
import getAppErrorMessage from "@saleor/utils/errors/app";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import ServiceInfo from "../ServiceInfo";
|
||||
import CustomAppInformation from "../CustomAppInformation";
|
||||
|
||||
export interface ServiceCreatePageFormData {
|
||||
export interface CustomAppCreatePageFormData {
|
||||
hasFullAccess: boolean;
|
||||
isActive: boolean;
|
||||
name: string;
|
||||
permissions: PermissionEnum[];
|
||||
}
|
||||
export interface ServiceCreatePageProps {
|
||||
export interface CustomAppCreatePageProps {
|
||||
disabled: boolean;
|
||||
errors: AccountErrorFragment[];
|
||||
errors: AppErrorFragment[];
|
||||
permissions: ShopInfo_shop_permissions[];
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
onBack: () => void;
|
||||
onSubmit: (data: ServiceCreatePageFormData) => void;
|
||||
onSubmit: (data: CustomAppCreatePageFormData) => void;
|
||||
}
|
||||
|
||||
const ServiceCreatePage: React.FC<ServiceCreatePageProps> = props => {
|
||||
const CustomAppCreatePage: React.FC<CustomAppCreatePageProps> = props => {
|
||||
const {
|
||||
disabled,
|
||||
errors,
|
||||
|
@ -45,7 +45,7 @@ const ServiceCreatePage: React.FC<ServiceCreatePageProps> = props => {
|
|||
} = props;
|
||||
const intl = useIntl();
|
||||
|
||||
const initialForm: ServiceCreatePageFormData = {
|
||||
const initialForm: CustomAppCreatePageFormData = {
|
||||
hasFullAccess: false,
|
||||
isActive: false,
|
||||
name: "",
|
||||
|
@ -53,24 +53,24 @@ const ServiceCreatePage: React.FC<ServiceCreatePageProps> = props => {
|
|||
};
|
||||
|
||||
const formErrors = getFormErrors(["permissions"], errors || []);
|
||||
const permissionsError = getAccountErrorMessage(formErrors.permissions, intl);
|
||||
const permissionsError = getAppErrorMessage(formErrors.permissions, intl);
|
||||
|
||||
return (
|
||||
<Form initial={initialForm} onSubmit={onSubmit} confirmLeave>
|
||||
{({ data, change, hasChanged, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.serviceAccounts)}
|
||||
{intl.formatMessage(sectionNames.apps)}
|
||||
</AppHeader>
|
||||
<PageHeader
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Create New Account",
|
||||
defaultMessage: "Create New App",
|
||||
description: "header"
|
||||
})}
|
||||
/>
|
||||
<Grid>
|
||||
<div>
|
||||
<ServiceInfo
|
||||
<CustomAppInformation
|
||||
data={data}
|
||||
disabled={disabled}
|
||||
errors={errors}
|
||||
|
@ -85,21 +85,21 @@ const ServiceCreatePage: React.FC<ServiceCreatePageProps> = props => {
|
|||
permissionsExceeded={false}
|
||||
onChange={change}
|
||||
fullAccessLabel={intl.formatMessage({
|
||||
defaultMessage: "User has full access to the store",
|
||||
defaultMessage: "Grant this app full access to the store",
|
||||
description: "checkbox label"
|
||||
})}
|
||||
description={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Expand or restrict user's permissions to access certain part of saleor system.",
|
||||
"Expand or restrict app permissions to access certain part of Saleor system.",
|
||||
description: "card description"
|
||||
})}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<AccountStatus
|
||||
<AppStatus
|
||||
data={data}
|
||||
disabled={disabled}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Service account is active",
|
||||
defaultMessage: "App is active",
|
||||
description: "checkbox label"
|
||||
})}
|
||||
onChange={change}
|
||||
|
@ -117,5 +117,5 @@ const ServiceCreatePage: React.FC<ServiceCreatePageProps> = props => {
|
|||
);
|
||||
};
|
||||
|
||||
ServiceCreatePage.displayName = "ServiceCreatePage";
|
||||
export default ServiceCreatePage;
|
||||
CustomAppCreatePage.displayName = "CustomAppCreatePage";
|
||||
export default CustomAppCreatePage;
|
2
src/apps/components/CustomAppCreatePage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CustomAppCreatePage";
|
||||
export { default } from "./CustomAppCreatePage";
|
|
@ -3,8 +3,6 @@ import Card from "@material-ui/core/Card";
|
|||
import CardContent from "@material-ui/core/CardContent";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import CloseIcon from "@material-ui/icons/Close";
|
||||
import Link from "@saleor/components/Link";
|
||||
|
@ -12,50 +10,16 @@ import useClipboard from "@saleor/hooks/useClipboard";
|
|||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
export interface ServiceDefaultTokenProps {
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export interface CustomAppDefaultTokenProps {
|
||||
apiUri: string;
|
||||
token: string;
|
||||
onApiUriClick: () => void;
|
||||
onTokenClose: () => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
cancel: {
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
closeContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
position: "relative",
|
||||
right: -theme.spacing(),
|
||||
top: -theme.spacing(1)
|
||||
},
|
||||
content: {
|
||||
display: "grid",
|
||||
gridColumnGap: theme.spacing(3),
|
||||
gridTemplateColumns: "1fr 60px",
|
||||
marginBottom: theme.spacing(3)
|
||||
},
|
||||
copy: {
|
||||
marginTop: theme.spacing(),
|
||||
position: "relative",
|
||||
right: theme.spacing(1)
|
||||
},
|
||||
paper: {
|
||||
background: fade(theme.palette.primary.main, 0.05),
|
||||
padding: theme.spacing(2, 3)
|
||||
},
|
||||
root: {
|
||||
boxShadow: "0px 5px 10px rgba(0, 0, 0, 0.05)"
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: "ServiceTokenCreateDialog"
|
||||
}
|
||||
);
|
||||
|
||||
const ServiceDefaultToken: React.FC<ServiceDefaultTokenProps> = props => {
|
||||
const CustomAppDefaultToken: React.FC<CustomAppDefaultTokenProps> = props => {
|
||||
const { apiUri, token, onApiUriClick, onTokenClose } = props;
|
||||
const classes = useStyles(props);
|
||||
const [copied, copy] = useClipboard();
|
||||
|
@ -112,5 +76,5 @@ const ServiceDefaultToken: React.FC<ServiceDefaultTokenProps> = props => {
|
|||
);
|
||||
};
|
||||
|
||||
ServiceDefaultToken.displayName = "ServiceDefaultToken";
|
||||
export default ServiceDefaultToken;
|
||||
CustomAppDefaultToken.displayName = "CustomAppDefaultToken";
|
||||
export default CustomAppDefaultToken;
|
2
src/apps/components/CustomAppDefaultToken/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CustomAppDefaultToken";
|
||||
export { default } from "./CustomAppDefaultToken";
|
38
src/apps/components/CustomAppDefaultToken/styles.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
cancel: {
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
closeContainer: {
|
||||
display: "flex",
|
||||
justifyContent: "flex-end",
|
||||
position: "relative",
|
||||
right: -theme.spacing(),
|
||||
top: -theme.spacing(1)
|
||||
},
|
||||
content: {
|
||||
display: "grid",
|
||||
gridColumnGap: theme.spacing(3),
|
||||
gridTemplateColumns: "1fr 60px",
|
||||
marginBottom: theme.spacing(3)
|
||||
},
|
||||
copy: {
|
||||
marginTop: theme.spacing(),
|
||||
position: "relative",
|
||||
right: theme.spacing(1)
|
||||
},
|
||||
paper: {
|
||||
background: fade(theme.palette.primary.main, 0.05),
|
||||
padding: theme.spacing(2, 3)
|
||||
},
|
||||
root: {
|
||||
boxShadow: "0px 5px 10px rgba(0, 0, 0, 0.05)"
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: "CustomAppTokenCreateDialog"
|
||||
}
|
||||
);
|
|
@ -1,6 +1,7 @@
|
|||
import { AppErrorFragment } from "@saleor/apps/types/AppErrorFragment";
|
||||
import AccountPermissions from "@saleor/components/AccountPermissions";
|
||||
import AccountStatus from "@saleor/components/AccountStatus";
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import AppStatus from "@saleor/components/AppStatus";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import Container from "@saleor/components/Container";
|
||||
|
@ -9,93 +10,95 @@ import Grid from "@saleor/components/Grid";
|
|||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import { ShopInfo_shop_permissions } from "@saleor/components/Shop/types/ShopInfo";
|
||||
import { AccountErrorFragment } from "@saleor/fragments/types/AccountErrorFragment";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import { ServiceDetails_serviceAccount } from "@saleor/services/types/ServiceDetails";
|
||||
import { PermissionEnum } from "@saleor/types/globalTypes";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import getAccountErrorMessage from "@saleor/utils/errors/account";
|
||||
import getAppErrorMessage from "@saleor/utils/errors/app";
|
||||
import WebhooksList from "@saleor/webhooks/components/WebhooksList";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import ServiceDefaultToken from "../ServiceDefaultToken";
|
||||
import ServiceInfo from "../ServiceInfo";
|
||||
import ServiceTokens from "../ServiceTokens";
|
||||
import { AppUpdate_appUpdate_app } from "../../types/AppUpdate";
|
||||
import CustomAppDefaultToken from "../CustomAppDefaultToken";
|
||||
import CustomAppInformation from "../CustomAppInformation";
|
||||
import CustomAppTokens from "../CustomAppTokens";
|
||||
|
||||
export interface ServiceDetailsPageFormData {
|
||||
export interface CustomAppDetailsPageFormData {
|
||||
hasFullAccess: boolean;
|
||||
isActive: boolean;
|
||||
name: string;
|
||||
permissions: PermissionEnum[];
|
||||
}
|
||||
export interface ServiceDetailsPageProps {
|
||||
export interface CustomAppDetailsPageProps {
|
||||
apiUri: string;
|
||||
disabled: boolean;
|
||||
errors: AccountErrorFragment[];
|
||||
errors: AppErrorFragment[];
|
||||
permissions: ShopInfo_shop_permissions[];
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
service: ServiceDetails_serviceAccount;
|
||||
app: AppUpdate_appUpdate_app;
|
||||
token: string;
|
||||
onApiUriClick: () => void;
|
||||
onBack: () => void;
|
||||
onTokenDelete: (id: string) => void;
|
||||
onDelete: () => void;
|
||||
onTokenClose: () => void;
|
||||
onTokenCreate: () => void;
|
||||
onSubmit: (data: ServiceDetailsPageFormData) => void;
|
||||
onSubmit: (data: CustomAppDetailsPageFormData) => void;
|
||||
onWebhookCreate: () => void;
|
||||
onWebhookRemove: (id: string) => void;
|
||||
navigateToWebhookDetails: (id: string) => () => void;
|
||||
}
|
||||
|
||||
const ServiceDetailsPage: React.FC<ServiceDetailsPageProps> = props => {
|
||||
const CustomAppDetailsPage: React.FC<CustomAppDetailsPageProps> = props => {
|
||||
const {
|
||||
apiUri,
|
||||
disabled,
|
||||
errors,
|
||||
permissions,
|
||||
saveButtonBarState,
|
||||
service,
|
||||
app,
|
||||
navigateToWebhookDetails,
|
||||
token,
|
||||
onApiUriClick,
|
||||
onBack,
|
||||
onDelete,
|
||||
onTokenClose,
|
||||
onTokenCreate,
|
||||
onTokenDelete,
|
||||
onSubmit
|
||||
onSubmit,
|
||||
onWebhookCreate,
|
||||
onWebhookRemove
|
||||
} = props;
|
||||
const intl = useIntl();
|
||||
|
||||
const formErrors = getFormErrors(["permissions"], errors || []);
|
||||
const permissionsError = getAccountErrorMessage(formErrors.permissions, intl);
|
||||
const webhooks = app?.webhooks;
|
||||
|
||||
const initialForm: ServiceDetailsPageFormData = {
|
||||
hasFullAccess: maybe(
|
||||
() =>
|
||||
permissions.filter(
|
||||
perm =>
|
||||
maybe(() => service.permissions, []).filter(
|
||||
userPerm => userPerm.code === perm.code
|
||||
).length === 0
|
||||
).length === 0,
|
||||
false
|
||||
),
|
||||
isActive: maybe(() => service.isActive, false),
|
||||
name: maybe(() => service.name, ""),
|
||||
permissions: maybe(() => service.permissions, []).map(perm => perm.code)
|
||||
const formErrors = getFormErrors(["permissions"], errors || []);
|
||||
const permissionsError = getAppErrorMessage(formErrors.permissions, intl);
|
||||
|
||||
const initialForm: CustomAppDetailsPageFormData = {
|
||||
hasFullAccess:
|
||||
permissions?.filter(
|
||||
perm =>
|
||||
app?.permissions?.filter(userPerm => userPerm.code === perm.code)
|
||||
.length === 0
|
||||
).length === 0 || false,
|
||||
isActive: !!app?.isActive,
|
||||
name: app?.name || "",
|
||||
permissions: app?.permissions?.map(perm => perm.code) || []
|
||||
};
|
||||
|
||||
return (
|
||||
<Form initial={initialForm} onSubmit={onSubmit} confirmLeave>
|
||||
{({ data, change, hasChanged, submit }) => (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>
|
||||
{intl.formatMessage(sectionNames.serviceAccounts)}
|
||||
{intl.formatMessage(sectionNames.apps)}
|
||||
</AppHeader>
|
||||
<PageHeader title={maybe(() => service.name)} />
|
||||
<PageHeader title={app?.name} />
|
||||
<Grid>
|
||||
<div>
|
||||
{token && (
|
||||
<>
|
||||
<ServiceDefaultToken
|
||||
<CustomAppDefaultToken
|
||||
apiUri={apiUri}
|
||||
token={token}
|
||||
onApiUriClick={onApiUriClick}
|
||||
|
@ -104,18 +107,25 @@ const ServiceDetailsPage: React.FC<ServiceDetailsPageProps> = props => {
|
|||
<CardSpacer />
|
||||
</>
|
||||
)}
|
||||
<ServiceInfo
|
||||
<CustomAppInformation
|
||||
data={data}
|
||||
disabled={disabled}
|
||||
errors={errors}
|
||||
onChange={change}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<ServiceTokens
|
||||
tokens={service?.tokens}
|
||||
<CustomAppTokens
|
||||
tokens={app?.tokens}
|
||||
onCreate={onTokenCreate}
|
||||
onDelete={onTokenDelete}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<WebhooksList
|
||||
webhooks={webhooks}
|
||||
onRemove={onWebhookRemove}
|
||||
onRowClick={navigateToWebhookDetails}
|
||||
onCreate={app?.isActive && onWebhookCreate}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<AccountPermissions
|
||||
|
@ -126,21 +136,21 @@ const ServiceDetailsPage: React.FC<ServiceDetailsPageProps> = props => {
|
|||
permissionsExceeded={false}
|
||||
onChange={change}
|
||||
fullAccessLabel={intl.formatMessage({
|
||||
defaultMessage: "User has full access to the store",
|
||||
defaultMessage: "Grant this app full access to the store",
|
||||
description: "checkbox label"
|
||||
})}
|
||||
description={intl.formatMessage({
|
||||
defaultMessage:
|
||||
"Expand or restrict user's permissions to access certain part of saleor system.",
|
||||
"Expand or restrict app permissions to access certain part of Saleor system.",
|
||||
description: "card description"
|
||||
})}
|
||||
/>
|
||||
<CardSpacer />
|
||||
<AccountStatus
|
||||
<AppStatus
|
||||
data={data}
|
||||
disabled={disabled}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Service account is active",
|
||||
defaultMessage: "App is active",
|
||||
description: "checkbox label"
|
||||
})}
|
||||
onChange={change}
|
||||
|
@ -152,7 +162,6 @@ const ServiceDetailsPage: React.FC<ServiceDetailsPageProps> = props => {
|
|||
state={saveButtonBarState}
|
||||
onCancel={onBack}
|
||||
onSave={submit}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
</Container>
|
||||
)}
|
||||
|
@ -160,5 +169,5 @@ const ServiceDetailsPage: React.FC<ServiceDetailsPageProps> = props => {
|
|||
);
|
||||
};
|
||||
|
||||
ServiceDetailsPage.displayName = "ServiceDetailsPage";
|
||||
export default ServiceDetailsPage;
|
||||
CustomAppDetailsPage.displayName = "CustomAppDetailsPage";
|
||||
export default CustomAppDetailsPage;
|
2
src/apps/components/CustomAppDetailsPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CustomAppDetailsPage";
|
||||
export { default } from "./CustomAppDetailsPage";
|
|
@ -1,24 +1,24 @@
|
|||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import { AppErrorFragment } from "@saleor/apps/types/AppErrorFragment";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import { AccountErrorFragment } from "@saleor/fragments/types/AccountErrorFragment";
|
||||
import { FormChange } from "@saleor/hooks/useForm";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import getAccountErrorMessage from "@saleor/utils/errors/account";
|
||||
import getAppErrorMessage from "@saleor/utils/errors/app";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
export interface ServiceInfoProps {
|
||||
export interface CustomAppInfoProps {
|
||||
data: {
|
||||
name: string;
|
||||
};
|
||||
disabled: boolean;
|
||||
errors: AccountErrorFragment[];
|
||||
errors: AppErrorFragment[];
|
||||
onChange: FormChange;
|
||||
}
|
||||
|
||||
const ServiceInfo: React.FC<ServiceInfoProps> = ({
|
||||
const CustomAppInformation: React.FC<CustomAppInfoProps> = ({
|
||||
data,
|
||||
disabled,
|
||||
errors,
|
||||
|
@ -32,7 +32,7 @@ const ServiceInfo: React.FC<ServiceInfoProps> = ({
|
|||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Service Account Information",
|
||||
defaultMessage: "App Information",
|
||||
description: "header"
|
||||
})}
|
||||
/>
|
||||
|
@ -41,10 +41,10 @@ const ServiceInfo: React.FC<ServiceInfoProps> = ({
|
|||
disabled={disabled}
|
||||
error={!!formErrors.name}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Account Name",
|
||||
description: "service account"
|
||||
defaultMessage: "App Name",
|
||||
description: "custom app name"
|
||||
})}
|
||||
helperText={getAccountErrorMessage(formErrors.name, intl)}
|
||||
helperText={getAppErrorMessage(formErrors.name, intl)}
|
||||
fullWidth
|
||||
name="name"
|
||||
value={data.name}
|
||||
|
@ -55,5 +55,5 @@ const ServiceInfo: React.FC<ServiceInfoProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
ServiceInfo.displayName = "ServiceInfo";
|
||||
export default ServiceInfo;
|
||||
CustomAppInformation.displayName = "CustomAppInformation";
|
||||
export default CustomAppInformation;
|
2
src/apps/components/CustomAppInformation/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CustomAppInformation";
|
||||
export { default } from "./CustomAppInformation";
|
|
@ -1,7 +1,6 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableHead from "@material-ui/core/TableHead";
|
||||
|
@ -10,42 +9,22 @@ import DeleteIcon from "@material-ui/icons/Delete";
|
|||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||
import Skeleton from "@saleor/components/Skeleton";
|
||||
import { ServiceDetailsFragment_tokens } from "@saleor/fragments/types/ServiceDetailsFragment";
|
||||
import { maybe, renderCollection } from "@saleor/misc";
|
||||
import { renderCollection } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface ServiceTokensProps {
|
||||
tokens: ServiceDetailsFragment_tokens[];
|
||||
import { AppUpdate_appUpdate_app_tokens } from "../../types/AppUpdate";
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export interface CustomAppTokensProps {
|
||||
tokens: Array<AppUpdate_appUpdate_app_tokens | null> | null;
|
||||
onCreate: () => void;
|
||||
onDelete: (id: string) => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
[theme.breakpoints.down("md")]: {
|
||||
colNote: {
|
||||
width: 200
|
||||
}
|
||||
},
|
||||
colActions: {
|
||||
textAlign: "right",
|
||||
width: 100
|
||||
},
|
||||
colKey: {
|
||||
width: 200
|
||||
},
|
||||
colNote: {},
|
||||
table: {
|
||||
tableLayout: "fixed"
|
||||
}
|
||||
}),
|
||||
{ name: "ServiceTokens" }
|
||||
);
|
||||
|
||||
const numberOfColumns = 3;
|
||||
|
||||
const ServiceTokens: React.FC<ServiceTokensProps> = props => {
|
||||
const CustomAppTokens: React.FC<CustomAppTokensProps> = props => {
|
||||
const { tokens, onCreate, onDelete } = props;
|
||||
const classes = useStyles(props);
|
||||
const intl = useIntl();
|
||||
|
@ -54,7 +33,7 @@ const ServiceTokens: React.FC<ServiceTokensProps> = props => {
|
|||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Service Account Information",
|
||||
defaultMessage: "Tokens",
|
||||
description: "header"
|
||||
})}
|
||||
toolbar={
|
||||
|
@ -75,7 +54,7 @@ const ServiceTokens: React.FC<ServiceTokensProps> = props => {
|
|||
<TableCell className={classes.colKey}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Key"
|
||||
description="service account key"
|
||||
description="custom app token key"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell className={classes.colActions}>
|
||||
|
@ -92,13 +71,10 @@ const ServiceTokens: React.FC<ServiceTokensProps> = props => {
|
|||
token => (
|
||||
<TableRow key={token ? token.id : "skeleton"}>
|
||||
<TableCell className={classes.colNote}>
|
||||
{maybe<React.ReactNode>(() => token.name, <Skeleton />)}
|
||||
{token?.name || <Skeleton />}
|
||||
</TableCell>
|
||||
<TableCell className={classes.colKey}>
|
||||
{maybe<React.ReactNode>(
|
||||
() => `**** ${token.authToken}`,
|
||||
<Skeleton />
|
||||
)}
|
||||
{token?.authToken ? `**** ${token.authToken}` : <Skeleton />}
|
||||
</TableCell>
|
||||
<TableCell className={classes.colActions}>
|
||||
<IconButton
|
||||
|
@ -124,5 +100,5 @@ const ServiceTokens: React.FC<ServiceTokensProps> = props => {
|
|||
);
|
||||
};
|
||||
|
||||
ServiceTokens.displayName = "ServiceTokens";
|
||||
export default ServiceTokens;
|
||||
CustomAppTokens.displayName = "CustomAppTokens";
|
||||
export default CustomAppTokens;
|
2
src/apps/components/CustomAppTokens/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CustomAppTokens";
|
||||
export { default } from "./CustomAppTokens";
|
23
src/apps/components/CustomAppTokens/styles.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
[theme.breakpoints.down("md")]: {
|
||||
colNote: {
|
||||
width: 200
|
||||
}
|
||||
},
|
||||
colActions: {
|
||||
textAlign: "right",
|
||||
width: 100
|
||||
},
|
||||
colKey: {
|
||||
width: 200
|
||||
},
|
||||
colNote: {},
|
||||
table: {
|
||||
tableLayout: "fixed"
|
||||
}
|
||||
}),
|
||||
{ name: "CustomAppTokens" }
|
||||
);
|
116
src/apps/components/CustomApps/CustomApps.tsx
Normal file
|
@ -0,0 +1,116 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import CardHeader from "@material-ui/core/CardHeader";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { renderCollection, stopPropagation } from "@saleor/misc";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { useStyles } from "../../styles";
|
||||
import { AppsList_apps_edges } from "../../types/AppsList";
|
||||
import AppsSkeleton from "../AppsSkeleton";
|
||||
import CardContainer from "../CardContainer";
|
||||
import DeactivatedText from "../DeactivatedText";
|
||||
|
||||
export interface CustomAppsProps {
|
||||
appsList: AppsList_apps_edges[];
|
||||
navigateToCustomApp: (id: string) => () => void;
|
||||
navigateToCustomAppCreate?: () => void;
|
||||
onRemove: (id: string) => void;
|
||||
}
|
||||
|
||||
const CustomApps: React.FC<CustomAppsProps> = ({
|
||||
appsList,
|
||||
navigateToCustomAppCreate,
|
||||
onRemove,
|
||||
navigateToCustomApp
|
||||
}) => {
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<CardContainer
|
||||
header={
|
||||
<>
|
||||
<CardHeader
|
||||
className={classes.title}
|
||||
action={
|
||||
!!navigateToCustomAppCreate && (
|
||||
<Button color="primary" onClick={navigateToCustomAppCreate}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Create App"
|
||||
description="create app button"
|
||||
/>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
title={
|
||||
<Typography
|
||||
className={classes.title}
|
||||
variant="h5"
|
||||
component="span"
|
||||
>
|
||||
<FormattedMessage {...commonMessages.customApps} />
|
||||
</Typography>
|
||||
}
|
||||
/>
|
||||
<hr className={classes.hr} />
|
||||
</>
|
||||
}
|
||||
>
|
||||
<TableBody>
|
||||
{renderCollection(
|
||||
appsList,
|
||||
(app, index) =>
|
||||
app ? (
|
||||
<TableRow
|
||||
key={app.node.id}
|
||||
className={classes.tableRow}
|
||||
onClick={navigateToCustomApp(app.node.id)}
|
||||
>
|
||||
<TableCell className={classes.colName}>
|
||||
<span data-tc="name" className={classes.appName}>
|
||||
{app.node.name}
|
||||
</span>
|
||||
{!app.node.isActive && (
|
||||
<div className={classes.statusWrapper}>
|
||||
<DeactivatedText />
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className={classes.colAction}>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={stopPropagation(() => onRemove(app.node.id))}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
<AppsSkeleton key={index} />
|
||||
),
|
||||
() => (
|
||||
<TableRow className={classes.tableRow}>
|
||||
<TableCell className={classes.colName}>
|
||||
<Typography className={classes.text} variant="body2">
|
||||
<FormattedMessage
|
||||
defaultMessage="Your custom created apps will be shown here."
|
||||
description="custom apps content"
|
||||
/>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</CardContainer>
|
||||
);
|
||||
};
|
||||
|
||||
CustomApps.displayName = "CustomApps";
|
||||
export default CustomApps;
|
2
src/apps/components/CustomApps/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./CustomApps";
|
||||
export { default } from "./CustomApps";
|
19
src/apps/components/DeactivatedText/DeactivatedText.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export const DeactivatedText: React.FC<{}> = () => {
|
||||
const classes = useStyles({});
|
||||
return (
|
||||
<Typography className={classes.root}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Deactivated"
|
||||
description="app deactivated"
|
||||
/>
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeactivatedText;
|
2
src/apps/components/DeactivatedText/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./DeactivatedText";
|
||||
export { default } from "./DeactivatedText";
|
26
src/apps/components/DeactivatedText/styles.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
root: {
|
||||
"&:before": {
|
||||
backgroundColor: theme.palette.error.main,
|
||||
borderRadius: "50%",
|
||||
content: "''",
|
||||
display: "block",
|
||||
height: 8,
|
||||
left: 0,
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
width: 8
|
||||
},
|
||||
color: theme.palette.error.main,
|
||||
display: "inline-block",
|
||||
marginLeft: theme.spacing(1.5),
|
||||
paddingLeft: theme.spacing(2),
|
||||
position: "relative"
|
||||
}
|
||||
}),
|
||||
{ name: "DeactivatedText" }
|
||||
);
|
133
src/apps/components/InstalledApps/InstalledApps.tsx
Normal file
|
@ -0,0 +1,133 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import IconButton from "@material-ui/core/IconButton";
|
||||
import TableBody from "@material-ui/core/TableBody";
|
||||
import TableCell from "@material-ui/core/TableCell";
|
||||
import TableFooter from "@material-ui/core/TableFooter";
|
||||
import TableRow from "@material-ui/core/TableRow";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import TablePagination from "@saleor/components/TablePagination";
|
||||
import { renderCollection, stopPropagation } from "@saleor/misc";
|
||||
import { ListProps } from "@saleor/types";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { useStyles } from "../../styles";
|
||||
import { AppsList_apps_edges } from "../../types/AppsList";
|
||||
import AppsSkeleton from "../AppsSkeleton";
|
||||
import CardContainer from "../CardContainer";
|
||||
import DeactivatedText from "../DeactivatedText";
|
||||
|
||||
export interface InstalledAppsProps extends ListProps {
|
||||
appsList: AppsList_apps_edges[];
|
||||
onRemove: (id: string) => void;
|
||||
onSettingsRowClick: (id: string) => () => void;
|
||||
}
|
||||
const numberOfColumns = 2;
|
||||
|
||||
const InstalledApps: React.FC<InstalledAppsProps> = ({
|
||||
appsList,
|
||||
onRemove,
|
||||
settings,
|
||||
disabled,
|
||||
onNextPage,
|
||||
onPreviousPage,
|
||||
onRowClick,
|
||||
onUpdateListSettings,
|
||||
onSettingsRowClick,
|
||||
pageInfo,
|
||||
...props
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
<CardContainer
|
||||
header={
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Thirdparty Apps",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TablePagination
|
||||
colSpan={numberOfColumns}
|
||||
settings={settings}
|
||||
hasNextPage={pageInfo && !disabled ? pageInfo.hasNextPage : false}
|
||||
onNextPage={onNextPage}
|
||||
onUpdateListSettings={onUpdateListSettings}
|
||||
hasPreviousPage={
|
||||
pageInfo && !disabled ? pageInfo.hasPreviousPage : false
|
||||
}
|
||||
onPreviousPage={onPreviousPage}
|
||||
/>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
<TableBody>
|
||||
{renderCollection(
|
||||
appsList,
|
||||
(app, index) =>
|
||||
app ? (
|
||||
<TableRow
|
||||
key={app.node.id}
|
||||
className={classes.tableRow}
|
||||
onClick={onSettingsRowClick(app.node.id)}
|
||||
>
|
||||
<TableCell className={classes.colName}>
|
||||
<span data-tc="name" className={classes.appName}>
|
||||
{app.node.name}
|
||||
</span>
|
||||
{!app.node.isActive && (
|
||||
<div className={classes.statusWrapper}>
|
||||
<DeactivatedText />
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className={classes.colAction}>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={stopPropagation(onRowClick(app.node.id))}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="About"
|
||||
description="about app"
|
||||
/>
|
||||
</Button>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={stopPropagation(() => onRemove(app.node.id))}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : (
|
||||
<AppsSkeleton key={index} />
|
||||
),
|
||||
() => (
|
||||
<TableRow className={classes.tableRow}>
|
||||
<TableCell className={classes.colName}>
|
||||
<Typography className={classes.text} variant="body2">
|
||||
<FormattedMessage
|
||||
defaultMessage="You don’t have any installed apps in your dashboard"
|
||||
description="apps content"
|
||||
/>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
)}
|
||||
</TableBody>
|
||||
</>
|
||||
</CardContainer>
|
||||
);
|
||||
};
|
||||
|
||||
InstalledApps.displayName = "InstalledApps";
|
||||
export default InstalledApps;
|
2
src/apps/components/InstalledApps/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./InstalledApps";
|
||||
export { default } from "./InstalledApps";
|
59
src/apps/components/Marketplace/Marketplace.tsx
Normal file
|
@ -0,0 +1,59 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import { useStyles } from "../../styles";
|
||||
|
||||
interface MarketplaceProps {
|
||||
link?: () => void;
|
||||
}
|
||||
|
||||
const Marketplace: React.FC<MarketplaceProps> = ({ link }) => {
|
||||
const intl = useIntl();
|
||||
const classes = useStyles({});
|
||||
|
||||
return (
|
||||
<div className={classes.appContainer}>
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Saleor Marketplace",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent className={classes.marketplaceContent}>
|
||||
{!!link ? (
|
||||
<>
|
||||
<Typography variant="body2">
|
||||
<FormattedMessage
|
||||
defaultMessage="Discover great free and paid apps in our Saleor Marketplace."
|
||||
description="marketplace content"
|
||||
/>
|
||||
</Typography>
|
||||
<Button color="primary" onClick={link}>
|
||||
<FormattedMessage
|
||||
defaultMessage="Visit Marketplace"
|
||||
description="marketplace button"
|
||||
/>
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Typography variant="body2">
|
||||
<FormattedMessage
|
||||
defaultMessage="Marketplace is coming soon"
|
||||
description="marketplace content"
|
||||
/>
|
||||
</Typography>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Marketplace.displayName = "Marketplace";
|
||||
export default Marketplace;
|
2
src/apps/components/Marketplace/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./Marketplace";
|
||||
export { default } from "./Marketplace";
|
|
@ -4,8 +4,6 @@ import DialogActions from "@material-ui/core/DialogActions";
|
|||
import DialogContent from "@material-ui/core/DialogContent";
|
||||
import DialogTitle from "@material-ui/core/DialogTitle";
|
||||
import Paper from "@material-ui/core/Paper";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
|
@ -19,7 +17,9 @@ import { buttonMessages } from "@saleor/intl";
|
|||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface ServiceTokenCreateDialogProps {
|
||||
import { useStyles } from "./styles";
|
||||
|
||||
export interface TokenCreateDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
open: boolean;
|
||||
token: string | undefined;
|
||||
|
@ -27,35 +27,15 @@ export interface ServiceTokenCreateDialogProps {
|
|||
onCreate: (name: string) => void;
|
||||
}
|
||||
|
||||
type ServiceTokenCreateStep = "form" | "summary";
|
||||
|
||||
const useStyles = makeStyles(
|
||||
theme => ({
|
||||
cancel: {
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
copy: {
|
||||
marginTop: theme.spacing(),
|
||||
position: "relative",
|
||||
right: theme.spacing(1)
|
||||
},
|
||||
paper: {
|
||||
background: fade(theme.palette.primary.main, 0.05),
|
||||
padding: theme.spacing(2, 3)
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: "ServiceTokenCreateDialog"
|
||||
}
|
||||
);
|
||||
type TokenCreateStep = "form" | "summary";
|
||||
|
||||
function handleCopy(token: string) {
|
||||
navigator.clipboard.writeText(token);
|
||||
}
|
||||
|
||||
const ServiceTokenCreateDialog: React.FC<ServiceTokenCreateDialogProps> = props => {
|
||||
const TokenCreateDialog: React.FC<TokenCreateDialogProps> = props => {
|
||||
const { confirmButtonState, open, token, onClose, onCreate } = props;
|
||||
const [step, setStep] = React.useState<ServiceTokenCreateStep>("form");
|
||||
const [step, setStep] = React.useState<TokenCreateStep>("form");
|
||||
const intl = useIntl();
|
||||
const classes = useStyles(props);
|
||||
|
||||
|
@ -155,5 +135,5 @@ const ServiceTokenCreateDialog: React.FC<ServiceTokenCreateDialogProps> = props
|
|||
);
|
||||
};
|
||||
|
||||
ServiceTokenCreateDialog.displayName = "ServiceTokenCreateDialog";
|
||||
export default ServiceTokenCreateDialog;
|
||||
TokenCreateDialog.displayName = "TokenCreateDialog";
|
||||
export default TokenCreateDialog;
|
2
src/apps/components/TokenCreateDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./TokenCreateDialog";
|
||||
export * from "./TokenCreateDialog";
|
22
src/apps/components/TokenCreateDialog/styles.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import { fade } from "@material-ui/core/styles/colorManipulator";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
cancel: {
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
copy: {
|
||||
marginTop: theme.spacing(),
|
||||
position: "relative",
|
||||
right: theme.spacing(1)
|
||||
},
|
||||
paper: {
|
||||
background: fade(theme.palette.primary.main, 0.05),
|
||||
padding: theme.spacing(2, 3)
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: "TokenCreateDialog"
|
||||
}
|
||||
);
|
|
@ -2,11 +2,9 @@ import Decorator from "@saleor/storybook/Decorator";
|
|||
import { storiesOf } from "@storybook/react";
|
||||
import React from "react";
|
||||
|
||||
import ServiceTokenDeleteDialog, {
|
||||
ServiceTokenDeleteDialogProps
|
||||
} from "./ServiceTokenDeleteDialog";
|
||||
import TokenDeleteDialog, { TokenDeleteDialogProps } from "./TokenDeleteDialog";
|
||||
|
||||
const props: ServiceTokenDeleteDialogProps = {
|
||||
const props: TokenDeleteDialogProps = {
|
||||
confirmButtonState: "default",
|
||||
name: "Slack",
|
||||
onClose: () => undefined,
|
||||
|
@ -14,6 +12,6 @@ const props: ServiceTokenDeleteDialogProps = {
|
|||
open: true
|
||||
};
|
||||
|
||||
storiesOf("Views / Services / Token delete", module)
|
||||
storiesOf("Views / Apps / Custom app details / Token delete", module)
|
||||
.addDecorator(Decorator)
|
||||
.add("default", () => <ServiceTokenDeleteDialog {...props} />);
|
||||
.add("default", () => <TokenDeleteDialog {...props} />);
|
|
@ -4,7 +4,7 @@ import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
|||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
export interface ServiceTokenDeleteDialogProps {
|
||||
export interface TokenDeleteDialogProps {
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
open: boolean;
|
||||
onConfirm: () => void;
|
||||
|
@ -12,7 +12,7 @@ export interface ServiceTokenDeleteDialogProps {
|
|||
name: string;
|
||||
}
|
||||
|
||||
const ServiceTokenDeleteDialog: React.FC<ServiceTokenDeleteDialogProps> = ({
|
||||
const TokenDeleteDialog: React.FC<TokenDeleteDialogProps> = ({
|
||||
name,
|
||||
confirmButtonState,
|
||||
onClose,
|
||||
|
@ -29,7 +29,7 @@ const ServiceTokenDeleteDialog: React.FC<ServiceTokenDeleteDialogProps> = ({
|
|||
onConfirm={onConfirm}
|
||||
variant="delete"
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Delete Service Account",
|
||||
defaultMessage: "Delete Token",
|
||||
description: "dialog title"
|
||||
})}
|
||||
>
|
||||
|
@ -46,5 +46,5 @@ const ServiceTokenDeleteDialog: React.FC<ServiceTokenDeleteDialogProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
ServiceTokenDeleteDialog.displayName = "ServiceTokenDeleteDialog";
|
||||
export default ServiceTokenDeleteDialog;
|
||||
TokenDeleteDialog.displayName = "TokenDeleteDialog";
|
||||
export default TokenDeleteDialog;
|
2
src/apps/components/TokenDeleteDialog/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./TokenDeleteDialog";
|
||||
export { default } from "./TokenDeleteDialog";
|
134
src/apps/fixtures.ts
Normal file
|
@ -0,0 +1,134 @@
|
|||
import {
|
||||
AppTypeEnum,
|
||||
JobStatusEnum,
|
||||
PermissionEnum
|
||||
} from "../types/globalTypes";
|
||||
import { App_app } from "./types/App";
|
||||
import { AppFetch_appFetchManifest_manifest } from "./types/AppFetch";
|
||||
import { AppsInstallations_appsInstallations } from "./types/AppsInstallations";
|
||||
import { AppsList_apps_edges } from "./types/AppsList";
|
||||
|
||||
export const appsList: AppsList_apps_edges[] = [
|
||||
{
|
||||
__typename: "AppCountableEdge",
|
||||
node: {
|
||||
__typename: "App",
|
||||
id: "QXBwOjE3Ng==",
|
||||
isActive: true,
|
||||
name: "app",
|
||||
type: AppTypeEnum.THIRDPARTY
|
||||
}
|
||||
},
|
||||
{
|
||||
__typename: "AppCountableEdge",
|
||||
node: {
|
||||
__typename: "App",
|
||||
id: "QXBwOjE3Ng==",
|
||||
isActive: false,
|
||||
name: "app1",
|
||||
type: AppTypeEnum.THIRDPARTY
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const customAppsList: AppsList_apps_edges[] = [
|
||||
{
|
||||
__typename: "AppCountableEdge",
|
||||
node: {
|
||||
__typename: "App",
|
||||
id: "QXBwOjE3Ng==",
|
||||
isActive: true,
|
||||
name: "app custom",
|
||||
type: AppTypeEnum.LOCAL
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const appsInProgress: AppsInstallations_appsInstallations[] = [
|
||||
{
|
||||
__typename: "AppInstallation",
|
||||
appName: "app",
|
||||
id: "QXBwSW5zdGFsbGF0aW9uOjk2",
|
||||
manifestUrl: "http://localhost:3000/manifest",
|
||||
message: "Failed to connect to app. Try later or contact with app support.",
|
||||
status: JobStatusEnum.FAILED
|
||||
},
|
||||
{
|
||||
__typename: "AppInstallation",
|
||||
appName: "app pending",
|
||||
id: "QXBwSW5zdGFsbGF0aW9uOjk2",
|
||||
manifestUrl: "http://localhost:3000/manifest",
|
||||
message: "Pending.",
|
||||
status: JobStatusEnum.PENDING
|
||||
},
|
||||
{
|
||||
__typename: "AppInstallation",
|
||||
appName: "app success",
|
||||
id: "QXBwSW5zdGFsbGF0aW9uOjk2",
|
||||
manifestUrl: "http://localhost:3000/manifest",
|
||||
message: "Success.",
|
||||
status: JobStatusEnum.SUCCESS
|
||||
}
|
||||
];
|
||||
|
||||
export const appDetails: App_app = {
|
||||
__typename: "App",
|
||||
aboutApp: "Lorem ipsum",
|
||||
accessToken: "token",
|
||||
appUrl: "http://localhost:8888/app",
|
||||
configurationUrl: "htpp://localhost:8888/configuration",
|
||||
created: "2020-06-02T12:24:26.818138+00:00",
|
||||
dataPrivacy: "Lorem ipsum",
|
||||
dataPrivacyUrl: "http://localhost:8888/app-data-privacy",
|
||||
homepageUrl: "http://localhost:8888/homepage",
|
||||
id: "QXBwOjE4MQ==",
|
||||
isActive: true,
|
||||
metadata: [],
|
||||
name: "app1",
|
||||
permissions: [
|
||||
{
|
||||
__typename: "Permission",
|
||||
code: PermissionEnum.MANAGE_ORDERS,
|
||||
name: "Manage orders."
|
||||
},
|
||||
{
|
||||
__typename: "Permission",
|
||||
code: PermissionEnum.MANAGE_USERS,
|
||||
name: "Manage customers."
|
||||
}
|
||||
],
|
||||
privateMetadata: [],
|
||||
supportUrl: "http://localhost:8888/support",
|
||||
tokens: [],
|
||||
type: AppTypeEnum.THIRDPARTY,
|
||||
version: "1.0.0",
|
||||
webhooks: []
|
||||
};
|
||||
|
||||
export const installApp: AppFetch_appFetchManifest_manifest = {
|
||||
__typename: "Manifest",
|
||||
|
||||
about: "Lorem ipsum",
|
||||
appUrl: null,
|
||||
configurationUrl: null,
|
||||
dataPrivacy: null,
|
||||
dataPrivacyUrl: null,
|
||||
homepageUrl: null,
|
||||
identifier: "app",
|
||||
name: "app",
|
||||
permissions: [
|
||||
{
|
||||
__typename: "Permission",
|
||||
code: PermissionEnum.MANAGE_USERS,
|
||||
name: "Manage users"
|
||||
},
|
||||
{
|
||||
__typename: "Permission",
|
||||
code: PermissionEnum.MANAGE_ORDERS,
|
||||
name: "Manage orders"
|
||||
}
|
||||
],
|
||||
supportUrl: null,
|
||||
tokenTargetUrl: null,
|
||||
version: "1.0"
|
||||
};
|
118
src/apps/index.tsx
Normal file
|
@ -0,0 +1,118 @@
|
|||
import { sectionNames } from "@saleor/intl";
|
||||
import WebhooksRoutes from "@saleor/webhooks";
|
||||
import { parse as parseQs } from "qs";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import { Route, RouteComponentProps, Switch } from "react-router-dom";
|
||||
|
||||
import { WindowTitle } from "../components/WindowTitle";
|
||||
import {
|
||||
AppDetailsUrlQueryParams,
|
||||
appInstallPath,
|
||||
AppInstallUrlQueryParams,
|
||||
AppListUrlQueryParams,
|
||||
appPath,
|
||||
appSettingsPath,
|
||||
appsListPath,
|
||||
customAppAddPath,
|
||||
customAppPath,
|
||||
CustomAppUrlQueryParams
|
||||
} from "./urls";
|
||||
import AppDetailsView from "./views/AppDetails";
|
||||
import AppDetailsSettingsView from "./views/AppDetailsSettings";
|
||||
import AppInstallView from "./views/AppInstall";
|
||||
import AppsListView from "./views/AppsList";
|
||||
import CustomAppCreateView from "./views/CustomAppCreate";
|
||||
import CustomAppDetailsView from "./views/CustomAppDetails";
|
||||
|
||||
const AppDetails: React.FC<RouteComponentProps<{ id: string }>> = ({
|
||||
match
|
||||
}) => {
|
||||
const qs = parseQs(location.search.substr(1));
|
||||
const params: AppDetailsUrlQueryParams = qs;
|
||||
|
||||
return (
|
||||
<AppDetailsView id={decodeURIComponent(match.params.id)} params={params} />
|
||||
);
|
||||
};
|
||||
|
||||
const AppDetailsSettings: React.FC<RouteComponentProps<{ id: string }>> = ({
|
||||
match
|
||||
}) => <AppDetailsSettingsView id={decodeURIComponent(match.params.id)} />;
|
||||
|
||||
const AppInstall: React.FC<RouteComponentProps> = props => {
|
||||
const qs = parseQs(location.search.substr(1));
|
||||
const params: AppInstallUrlQueryParams = qs;
|
||||
|
||||
return <AppInstallView params={params} {...props} />;
|
||||
};
|
||||
|
||||
interface CustomAppDetailsProps extends RouteComponentProps<{ id: string }> {
|
||||
token: string;
|
||||
onTokenClose: () => void;
|
||||
}
|
||||
|
||||
const CustomAppDetails: React.FC<CustomAppDetailsProps> = ({
|
||||
match,
|
||||
token,
|
||||
onTokenClose
|
||||
}) => {
|
||||
const qs = parseQs(location.search.substr(1));
|
||||
const params: CustomAppUrlQueryParams = qs;
|
||||
|
||||
return (
|
||||
<CustomAppDetailsView
|
||||
id={decodeURIComponent(match.params.id)}
|
||||
params={params}
|
||||
token={token}
|
||||
onTokenClose={onTokenClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const AppsList: React.FC<RouteComponentProps> = () => {
|
||||
const qs = parseQs(location.search.substr(1));
|
||||
const params: AppListUrlQueryParams = qs;
|
||||
|
||||
return <AppsListView params={params} />;
|
||||
};
|
||||
const Component = () => {
|
||||
const intl = useIntl();
|
||||
const [token, setToken] = React.useState<string>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle title={intl.formatMessage(sectionNames.apps)} />
|
||||
<Switch>
|
||||
<Route exact path={appsListPath} component={AppsList} />
|
||||
<Route
|
||||
exact
|
||||
path={customAppAddPath}
|
||||
render={() => <CustomAppCreateView setToken={setToken} />}
|
||||
/>
|
||||
<Route exact path={appInstallPath} component={AppInstall} />
|
||||
<Route exact path={appPath(":id")} component={AppDetails} />
|
||||
<Route
|
||||
exact
|
||||
path={appSettingsPath(":id")}
|
||||
component={AppDetailsSettings}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path={customAppPath(":id")}
|
||||
render={props => (
|
||||
<CustomAppDetails
|
||||
{...props}
|
||||
token={token}
|
||||
onTokenClose={() => setToken(null)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<WebhooksRoutes />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Component;
|
269
src/apps/mutations.ts
Normal file
|
@ -0,0 +1,269 @@
|
|||
import { appFragment } from "@saleor/fragments/apps";
|
||||
import { appErrorFragment } from "@saleor/fragments/errors";
|
||||
import { webhooksFragment } from "@saleor/fragments/webhooks";
|
||||
import makeMutation from "@saleor/hooks/makeMutation";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { AppActivate, AppActivateVariables } from "./types/AppActivate";
|
||||
import { AppCreate, AppCreateVariables } from "./types/AppCreate";
|
||||
import { AppDeactivate, AppDeactivateVariables } from "./types/AppDeactivate";
|
||||
import { AppDelete, AppDeleteVariables } from "./types/AppDelete";
|
||||
import {
|
||||
AppDeleteFailedInstallation,
|
||||
AppDeleteFailedInstallationVariables
|
||||
} from "./types/AppDeleteFailedInstallation";
|
||||
import { AppFetch, AppFetchVariables } from "./types/AppFetch";
|
||||
import { AppInstall, AppInstallVariables } from "./types/AppInstall";
|
||||
import {
|
||||
AppRetryInstall,
|
||||
AppRetryInstallVariables
|
||||
} from "./types/AppRetryInstall";
|
||||
import {
|
||||
AppTokenCreate,
|
||||
AppTokenCreateVariables
|
||||
} from "./types/AppTokenCreate";
|
||||
import {
|
||||
AppTokenDelete,
|
||||
AppTokenDeleteVariables
|
||||
} from "./types/AppTokenDelete";
|
||||
import { AppUpdate, AppUpdateVariables } from "./types/AppUpdate";
|
||||
|
||||
export const appCreateMutation = gql`
|
||||
${appFragment}
|
||||
${webhooksFragment}
|
||||
${appErrorFragment}
|
||||
mutation AppCreate($input: AppInput!) {
|
||||
appCreate(input: $input) {
|
||||
authToken
|
||||
app {
|
||||
...AppFragment
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appDeleteMutation = gql`
|
||||
${appFragment}
|
||||
${webhooksFragment}
|
||||
${appErrorFragment}
|
||||
mutation AppDelete($id: ID!) {
|
||||
appDelete(id: $id) {
|
||||
app {
|
||||
...AppFragment
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appDeleteFailedInstallationMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppDeleteFailedInstallation($id: ID!) {
|
||||
appDeleteFailedInstallation(id: $id) {
|
||||
appInstallation {
|
||||
id
|
||||
status
|
||||
appName
|
||||
message
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appFetchMutation = gql`
|
||||
mutation AppFetch($manifestUrl: String!) {
|
||||
appFetchManifest(manifestUrl: $manifestUrl) {
|
||||
manifest {
|
||||
identifier
|
||||
version
|
||||
about
|
||||
name
|
||||
appUrl
|
||||
configurationUrl
|
||||
tokenTargetUrl
|
||||
dataPrivacy
|
||||
dataPrivacyUrl
|
||||
homepageUrl
|
||||
supportUrl
|
||||
permissions {
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appInstallMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppInstall($input: AppInstallInput!) {
|
||||
appInstall(input: $input) {
|
||||
appInstallation {
|
||||
id
|
||||
status
|
||||
appName
|
||||
manifestUrl
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appRetryInstallMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppRetryInstall($id: ID!) {
|
||||
appRetryInstall(id: $id) {
|
||||
appInstallation {
|
||||
id
|
||||
status
|
||||
appName
|
||||
manifestUrl
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appActivateMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppActivate($id: ID!) {
|
||||
appActivate(id: $id) {
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appDeactivateMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppDeactivate($id: ID!) {
|
||||
appDeactivate(id: $id) {
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appUpdateMutation = gql`
|
||||
${appErrorFragment}
|
||||
${appFragment}
|
||||
${webhooksFragment}
|
||||
mutation AppUpdate($id: ID!, $input: AppInput!) {
|
||||
appUpdate(id: $id, input: $input) {
|
||||
app {
|
||||
...AppFragment
|
||||
permissions {
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
message
|
||||
permissions
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appTokenCreateMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppTokenCreate($input: AppTokenInput!) {
|
||||
appTokenCreate(input: $input) {
|
||||
appToken {
|
||||
name
|
||||
authToken
|
||||
id
|
||||
}
|
||||
authToken
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const appTokenDeleteMutation = gql`
|
||||
${appErrorFragment}
|
||||
mutation AppTokenDelete($id: ID!) {
|
||||
appTokenDelete(id: $id) {
|
||||
appToken {
|
||||
name
|
||||
authToken
|
||||
id
|
||||
}
|
||||
errors: appErrors {
|
||||
...AppErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useAppCreateMutation = makeMutation<AppCreate, AppCreateVariables>(
|
||||
appCreateMutation
|
||||
);
|
||||
|
||||
export const useAppDeleteMutation = makeMutation<AppDelete, AppDeleteVariables>(
|
||||
appDeleteMutation
|
||||
);
|
||||
|
||||
export const useAppDeleteFailedInstallationMutation = makeMutation<
|
||||
AppDeleteFailedInstallation,
|
||||
AppDeleteFailedInstallationVariables
|
||||
>(appDeleteFailedInstallationMutation);
|
||||
|
||||
export const useAppInstallMutation = makeMutation<
|
||||
AppInstall,
|
||||
AppInstallVariables
|
||||
>(appInstallMutation);
|
||||
|
||||
export const useAppRetryInstallMutation = makeMutation<
|
||||
AppRetryInstall,
|
||||
AppRetryInstallVariables
|
||||
>(appRetryInstallMutation);
|
||||
|
||||
export const useAppManifestFetchMutation = makeMutation<
|
||||
AppFetch,
|
||||
AppFetchVariables
|
||||
>(appFetchMutation);
|
||||
|
||||
export const useAppActivateMutation = makeMutation<
|
||||
AppActivate,
|
||||
AppActivateVariables
|
||||
>(appActivateMutation);
|
||||
|
||||
export const useAppDeactivateMutation = makeMutation<
|
||||
AppDeactivate,
|
||||
AppDeactivateVariables
|
||||
>(appDeactivateMutation);
|
||||
|
||||
export const useAppUpdateMutation = makeMutation<AppUpdate, AppUpdateVariables>(
|
||||
appUpdateMutation
|
||||
);
|
||||
|
||||
export const useAppTokenCreateMutation = makeMutation<
|
||||
AppTokenCreate,
|
||||
AppTokenCreateVariables
|
||||
>(appTokenCreateMutation);
|
||||
|
||||
export const useAppTokenDeleteMutation = makeMutation<
|
||||
AppTokenDelete,
|
||||
AppTokenDeleteVariables
|
||||
>(appTokenDeleteMutation);
|
83
src/apps/queries.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { appFragment } from "@saleor/fragments/apps";
|
||||
import { webhooksFragment } from "@saleor/fragments/webhooks";
|
||||
import makeQuery from "@saleor/hooks/makeQuery";
|
||||
import gql from "graphql-tag";
|
||||
|
||||
import { App, AppVariables } from "./types/App";
|
||||
import { AppsInstallations } from "./types/AppsInstallations";
|
||||
import { AppsList, AppsListVariables } from "./types/AppsList";
|
||||
|
||||
const appsList = gql`
|
||||
query AppsList(
|
||||
$before: String
|
||||
$after: String
|
||||
$first: Int
|
||||
$last: Int
|
||||
$sort: AppSortingInput
|
||||
$filter: AppFilterInput
|
||||
) {
|
||||
apps(
|
||||
before: $before
|
||||
after: $after
|
||||
first: $first
|
||||
last: $last
|
||||
sortBy: $sort
|
||||
filter: $filter
|
||||
) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
totalCount
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
name
|
||||
isActive
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const appsInProgressList = gql`
|
||||
query AppsInstallations {
|
||||
appsInstallations {
|
||||
status
|
||||
message
|
||||
appName
|
||||
manifestUrl
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const appDetails = gql`
|
||||
${appFragment}
|
||||
${webhooksFragment}
|
||||
query App($id: ID!) {
|
||||
app(id: $id) {
|
||||
...AppFragment
|
||||
aboutApp
|
||||
permissions {
|
||||
code
|
||||
name
|
||||
}
|
||||
dataPrivacy
|
||||
dataPrivacyUrl
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const useAppsListQuery = makeQuery<AppsList, AppsListVariables>(
|
||||
appsList
|
||||
);
|
||||
|
||||
export const useAppsInProgressListQuery = makeQuery<AppsInstallations, {}>(
|
||||
appsInProgressList
|
||||
);
|
||||
|
||||
export const useAppDetails = makeQuery<App, AppVariables>(appDetails);
|
204
src/apps/styles.ts
Normal file
|
@ -0,0 +1,204 @@
|
|||
import { makeStyles } from "@material-ui/core/styles";
|
||||
|
||||
export const useStyles = makeStyles(
|
||||
theme => ({
|
||||
[theme.breakpoints.up("lg")]: {
|
||||
colName: {
|
||||
"&&": {
|
||||
width: "auto"
|
||||
}
|
||||
}
|
||||
},
|
||||
alignRight: {
|
||||
textAlign: "right"
|
||||
},
|
||||
appContainer: {
|
||||
marginBottom: theme.spacing(3)
|
||||
},
|
||||
appContent: {
|
||||
"&:last-child": {
|
||||
padding: "0!important"
|
||||
},
|
||||
padding: 0
|
||||
},
|
||||
appHeader: {
|
||||
marginBottom: theme.spacing(3)
|
||||
},
|
||||
appHeaderLinks: {
|
||||
"& img": {
|
||||
marginRight: theme.spacing(1)
|
||||
},
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
padding: theme.spacing(2, 0)
|
||||
},
|
||||
appName: {
|
||||
color: theme.palette.primary.main
|
||||
},
|
||||
colAction: {
|
||||
"&&": {
|
||||
paddingRight: theme.spacing(1),
|
||||
textAlign: "right"
|
||||
},
|
||||
textAlign: "right"
|
||||
},
|
||||
colInstallAction: {
|
||||
"& > *": {
|
||||
display: "inline-flex"
|
||||
}
|
||||
},
|
||||
colName: {
|
||||
paddingLeft: 0,
|
||||
width: theme.spacing(30)
|
||||
},
|
||||
colSpinner: {
|
||||
"& svg": {
|
||||
textAlign: "right"
|
||||
},
|
||||
paddingLeft: theme.spacing(3),
|
||||
paddingRight: theme.spacing(2)
|
||||
},
|
||||
customTooltip: {
|
||||
"& > div": {
|
||||
backgroundColor: theme.palette.error.main,
|
||||
borderRadius: theme.spacing(1),
|
||||
color: theme.palette.primary.contrastText,
|
||||
padding: theme.spacing(2)
|
||||
},
|
||||
padding: "0!important"
|
||||
},
|
||||
error: {
|
||||
"& svg": {
|
||||
bottom: theme.spacing(0.2),
|
||||
marginLeft: theme.spacing(0.6),
|
||||
position: "relative"
|
||||
},
|
||||
color: theme.palette.error.main,
|
||||
margin: theme.spacing(0, 1, 0.7, 0)
|
||||
},
|
||||
headerLinkContainer: {
|
||||
"& span": {
|
||||
fontWeight: 500
|
||||
},
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
fontSize: theme.spacing(2),
|
||||
fontWeight: 500,
|
||||
lineHeight: 1.2,
|
||||
marginRight: theme.spacing(3),
|
||||
padding: 0,
|
||||
textTransform: "none"
|
||||
},
|
||||
hr: {
|
||||
border: "none",
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
height: 0,
|
||||
marginBottom: 0,
|
||||
marginTop: 0,
|
||||
width: "100%"
|
||||
},
|
||||
installAppContainer: {
|
||||
"& > div": {
|
||||
position: "relative"
|
||||
},
|
||||
"& img": {
|
||||
position: "relative"
|
||||
},
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
padding: theme.spacing(2, 0),
|
||||
position: "relative",
|
||||
width: theme.spacing(35)
|
||||
},
|
||||
installCard: {
|
||||
"&:before": {
|
||||
backgroundColor: theme.palette.divider,
|
||||
content: "''",
|
||||
height: 2,
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
transform: "translateY(-50%)",
|
||||
width: theme.spacing(30)
|
||||
},
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
position: "relative"
|
||||
},
|
||||
installIcon: {
|
||||
alignItems: "center",
|
||||
backgroundColor: theme.palette.divider,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
height: theme.spacing(9),
|
||||
justifyContent: "center",
|
||||
overflow: "hidden",
|
||||
width: theme.spacing(9)
|
||||
},
|
||||
installPermissionTitle: {
|
||||
fontWeight: 500
|
||||
},
|
||||
installPrivacyText: {
|
||||
"& a": {
|
||||
color: theme.palette.primary.main,
|
||||
textDecoration: "none"
|
||||
},
|
||||
color: theme.palette.text.hint
|
||||
},
|
||||
installSaleorIcon: {
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
border: "none"
|
||||
},
|
||||
installSpacer: {
|
||||
margin: theme.spacing(2, 0)
|
||||
},
|
||||
installText: {
|
||||
color: theme.palette.primary.contrastText
|
||||
},
|
||||
linkContainer: {
|
||||
fontWeight: 500,
|
||||
marginTop: theme.spacing(1.5)
|
||||
},
|
||||
marketplaceContent: {
|
||||
"& button": {
|
||||
marginTop: theme.spacing(1)
|
||||
},
|
||||
"&:last-child": {
|
||||
padding: theme.spacing(2, 3, 2, 3)
|
||||
},
|
||||
padding: theme.spacing(1)
|
||||
},
|
||||
permissionsContainer: {
|
||||
"& li": {
|
||||
"&:last-child": {
|
||||
marginBottom: 0
|
||||
},
|
||||
marginBottom: theme.spacing(1)
|
||||
},
|
||||
paddingLeft: theme.spacing(2)
|
||||
},
|
||||
retryBtnCol: {
|
||||
paddingRight: theme.spacing(1),
|
||||
width: theme.spacing(14)
|
||||
},
|
||||
statusWrapper: {
|
||||
display: "inline-block",
|
||||
marginLeft: theme.spacing(2.5)
|
||||
},
|
||||
table: {
|
||||
tableLayout: "fixed"
|
||||
},
|
||||
tableRow: {
|
||||
cursor: "pointer"
|
||||
},
|
||||
text: {
|
||||
color: theme.palette.text.secondary
|
||||
},
|
||||
title: {
|
||||
flex: 1,
|
||||
fontWeight: 500,
|
||||
lineHeight: 1
|
||||
}
|
||||
}),
|
||||
{ name: "AppList" }
|
||||
);
|
79
src/apps/types/App.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppTypeEnum, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: App
|
||||
// ====================================================
|
||||
|
||||
export interface App_app_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface App_app_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface App_app_tokens {
|
||||
__typename: "AppToken";
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface App_app_webhooks_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface App_app_webhooks {
|
||||
__typename: "Webhook";
|
||||
id: string;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
app: App_app_webhooks_app;
|
||||
}
|
||||
|
||||
export interface App_app_permissions {
|
||||
__typename: "Permission";
|
||||
code: PermissionEnum;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface App_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
created: any | null;
|
||||
isActive: boolean | null;
|
||||
type: AppTypeEnum | null;
|
||||
homepageUrl: string | null;
|
||||
appUrl: string | null;
|
||||
configurationUrl: string | null;
|
||||
supportUrl: string | null;
|
||||
version: string | null;
|
||||
accessToken: string | null;
|
||||
privateMetadata: (App_app_privateMetadata | null)[];
|
||||
metadata: (App_app_metadata | null)[];
|
||||
tokens: (App_app_tokens | null)[] | null;
|
||||
webhooks: (App_app_webhooks | null)[] | null;
|
||||
aboutApp: string | null;
|
||||
permissions: (App_app_permissions | null)[] | null;
|
||||
dataPrivacy: string | null;
|
||||
dataPrivacyUrl: string | null;
|
||||
}
|
||||
|
||||
export interface App {
|
||||
app: App_app | null;
|
||||
}
|
||||
|
||||
export interface AppVariables {
|
||||
id: string;
|
||||
}
|
30
src/apps/types/AppActivate.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppActivate
|
||||
// ====================================================
|
||||
|
||||
export interface AppActivate_appActivate_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppActivate_appActivate {
|
||||
__typename: "AppActivate";
|
||||
errors: AppActivate_appActivate_errors[];
|
||||
}
|
||||
|
||||
export interface AppActivate {
|
||||
appActivate: AppActivate_appActivate | null;
|
||||
}
|
||||
|
||||
export interface AppActivateVariables {
|
||||
id: string;
|
||||
}
|
84
src/apps/types/AppCreate.ts
Normal file
|
@ -0,0 +1,84 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppInput, AppTypeEnum, AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppCreate
|
||||
// ====================================================
|
||||
|
||||
export interface AppCreate_appCreate_app_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate_app_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate_app_tokens {
|
||||
__typename: "AppToken";
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate_app_webhooks_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate_app_webhooks {
|
||||
__typename: "Webhook";
|
||||
id: string;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
app: AppCreate_appCreate_app_webhooks_app;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
created: any | null;
|
||||
isActive: boolean | null;
|
||||
type: AppTypeEnum | null;
|
||||
homepageUrl: string | null;
|
||||
appUrl: string | null;
|
||||
configurationUrl: string | null;
|
||||
supportUrl: string | null;
|
||||
version: string | null;
|
||||
accessToken: string | null;
|
||||
privateMetadata: (AppCreate_appCreate_app_privateMetadata | null)[];
|
||||
metadata: (AppCreate_appCreate_app_metadata | null)[];
|
||||
tokens: (AppCreate_appCreate_app_tokens | null)[] | null;
|
||||
webhooks: (AppCreate_appCreate_app_webhooks | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppCreate_appCreate {
|
||||
__typename: "AppCreate";
|
||||
authToken: string | null;
|
||||
app: AppCreate_appCreate_app | null;
|
||||
errors: AppCreate_appCreate_errors[];
|
||||
}
|
||||
|
||||
export interface AppCreate {
|
||||
appCreate: AppCreate_appCreate | null;
|
||||
}
|
||||
|
||||
export interface AppCreateVariables {
|
||||
input: AppInput;
|
||||
}
|
30
src/apps/types/AppDeactivate.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppDeactivate
|
||||
// ====================================================
|
||||
|
||||
export interface AppDeactivate_appDeactivate_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppDeactivate_appDeactivate {
|
||||
__typename: "AppDeactivate";
|
||||
errors: AppDeactivate_appDeactivate_errors[];
|
||||
}
|
||||
|
||||
export interface AppDeactivate {
|
||||
appDeactivate: AppDeactivate_appDeactivate | null;
|
||||
}
|
||||
|
||||
export interface AppDeactivateVariables {
|
||||
id: string;
|
||||
}
|
83
src/apps/types/AppDelete.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppTypeEnum, AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppDelete
|
||||
// ====================================================
|
||||
|
||||
export interface AppDelete_appDelete_app_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete_app_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete_app_tokens {
|
||||
__typename: "AppToken";
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete_app_webhooks_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete_app_webhooks {
|
||||
__typename: "Webhook";
|
||||
id: string;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
app: AppDelete_appDelete_app_webhooks_app;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
created: any | null;
|
||||
isActive: boolean | null;
|
||||
type: AppTypeEnum | null;
|
||||
homepageUrl: string | null;
|
||||
appUrl: string | null;
|
||||
configurationUrl: string | null;
|
||||
supportUrl: string | null;
|
||||
version: string | null;
|
||||
accessToken: string | null;
|
||||
privateMetadata: (AppDelete_appDelete_app_privateMetadata | null)[];
|
||||
metadata: (AppDelete_appDelete_app_metadata | null)[];
|
||||
tokens: (AppDelete_appDelete_app_tokens | null)[] | null;
|
||||
webhooks: (AppDelete_appDelete_app_webhooks | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppDelete_appDelete {
|
||||
__typename: "AppDelete";
|
||||
app: AppDelete_appDelete_app | null;
|
||||
errors: AppDelete_appDelete_errors[];
|
||||
}
|
||||
|
||||
export interface AppDelete {
|
||||
appDelete: AppDelete_appDelete | null;
|
||||
}
|
||||
|
||||
export interface AppDeleteVariables {
|
||||
id: string;
|
||||
}
|
39
src/apps/types/AppDeleteFailedInstallation.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { JobStatusEnum, AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppDeleteFailedInstallation
|
||||
// ====================================================
|
||||
|
||||
export interface AppDeleteFailedInstallation_appDeleteFailedInstallation_appInstallation {
|
||||
__typename: "AppInstallation";
|
||||
id: string;
|
||||
status: JobStatusEnum;
|
||||
appName: string;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AppDeleteFailedInstallation_appDeleteFailedInstallation_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppDeleteFailedInstallation_appDeleteFailedInstallation {
|
||||
__typename: "AppDeleteFailedInstallation";
|
||||
appInstallation: AppDeleteFailedInstallation_appDeleteFailedInstallation_appInstallation | null;
|
||||
errors: AppDeleteFailedInstallation_appDeleteFailedInstallation_errors[];
|
||||
}
|
||||
|
||||
export interface AppDeleteFailedInstallation {
|
||||
appDeleteFailedInstallation: AppDeleteFailedInstallation_appDeleteFailedInstallation | null;
|
||||
}
|
||||
|
||||
export interface AppDeleteFailedInstallationVariables {
|
||||
id: string;
|
||||
}
|
17
src/apps/types/AppErrorFragment.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: AppErrorFragment
|
||||
// ====================================================
|
||||
|
||||
export interface AppErrorFragment {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
53
src/apps/types/AppFetch.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { PermissionEnum, AppErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppFetch
|
||||
// ====================================================
|
||||
|
||||
export interface AppFetch_appFetchManifest_manifest_permissions {
|
||||
__typename: "Permission";
|
||||
code: PermissionEnum;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AppFetch_appFetchManifest_manifest {
|
||||
__typename: "Manifest";
|
||||
identifier: string;
|
||||
version: string;
|
||||
about: string | null;
|
||||
name: string;
|
||||
appUrl: string | null;
|
||||
configurationUrl: string | null;
|
||||
tokenTargetUrl: string | null;
|
||||
dataPrivacy: string | null;
|
||||
dataPrivacyUrl: string | null;
|
||||
homepageUrl: string | null;
|
||||
supportUrl: string | null;
|
||||
permissions: (AppFetch_appFetchManifest_manifest_permissions | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AppFetch_appFetchManifest_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppFetch_appFetchManifest {
|
||||
__typename: "AppFetchManifest";
|
||||
manifest: AppFetch_appFetchManifest_manifest | null;
|
||||
errors: AppFetch_appFetchManifest_errors[];
|
||||
}
|
||||
|
||||
export interface AppFetch {
|
||||
appFetchManifest: AppFetch_appFetchManifest | null;
|
||||
}
|
||||
|
||||
export interface AppFetchVariables {
|
||||
manifestUrl: string;
|
||||
}
|
61
src/apps/types/AppFragment.ts
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppTypeEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: AppFragment
|
||||
// ====================================================
|
||||
|
||||
export interface AppFragment_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppFragment_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppFragment_tokens {
|
||||
__typename: "AppToken";
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppFragment_webhooks_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppFragment_webhooks {
|
||||
__typename: "Webhook";
|
||||
id: string;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
app: AppFragment_webhooks_app;
|
||||
}
|
||||
|
||||
export interface AppFragment {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
created: any | null;
|
||||
isActive: boolean | null;
|
||||
type: AppTypeEnum | null;
|
||||
homepageUrl: string | null;
|
||||
appUrl: string | null;
|
||||
configurationUrl: string | null;
|
||||
supportUrl: string | null;
|
||||
version: string | null;
|
||||
accessToken: string | null;
|
||||
privateMetadata: (AppFragment_privateMetadata | null)[];
|
||||
metadata: (AppFragment_metadata | null)[];
|
||||
tokens: (AppFragment_tokens | null)[] | null;
|
||||
webhooks: (AppFragment_webhooks | null)[] | null;
|
||||
}
|
39
src/apps/types/AppInstall.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppInstallInput, JobStatusEnum, AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppInstall
|
||||
// ====================================================
|
||||
|
||||
export interface AppInstall_appInstall_appInstallation {
|
||||
__typename: "AppInstallation";
|
||||
id: string;
|
||||
status: JobStatusEnum;
|
||||
appName: string;
|
||||
manifestUrl: string;
|
||||
}
|
||||
|
||||
export interface AppInstall_appInstall_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppInstall_appInstall {
|
||||
__typename: "AppInstall";
|
||||
appInstallation: AppInstall_appInstall_appInstallation | null;
|
||||
errors: AppInstall_appInstall_errors[];
|
||||
}
|
||||
|
||||
export interface AppInstall {
|
||||
appInstall: AppInstall_appInstall | null;
|
||||
}
|
||||
|
||||
export interface AppInstallVariables {
|
||||
input: AppInstallInput;
|
||||
}
|
39
src/apps/types/AppRetryInstall.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { JobStatusEnum, AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppRetryInstall
|
||||
// ====================================================
|
||||
|
||||
export interface AppRetryInstall_appRetryInstall_appInstallation {
|
||||
__typename: "AppInstallation";
|
||||
id: string;
|
||||
status: JobStatusEnum;
|
||||
appName: string;
|
||||
manifestUrl: string;
|
||||
}
|
||||
|
||||
export interface AppRetryInstall_appRetryInstall_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppRetryInstall_appRetryInstall {
|
||||
__typename: "AppRetryInstall";
|
||||
appInstallation: AppRetryInstall_appRetryInstall_appInstallation | null;
|
||||
errors: AppRetryInstall_appRetryInstall_errors[];
|
||||
}
|
||||
|
||||
export interface AppRetryInstall {
|
||||
appRetryInstall: AppRetryInstall_appRetryInstall | null;
|
||||
}
|
||||
|
||||
export interface AppRetryInstallVariables {
|
||||
id: string;
|
||||
}
|
39
src/apps/types/AppTokenCreate.ts
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppTokenInput, AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppTokenCreate
|
||||
// ====================================================
|
||||
|
||||
export interface AppTokenCreate_appTokenCreate_appToken {
|
||||
__typename: "AppToken";
|
||||
name: string | null;
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface AppTokenCreate_appTokenCreate_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppTokenCreate_appTokenCreate {
|
||||
__typename: "AppTokenCreate";
|
||||
appToken: AppTokenCreate_appTokenCreate_appToken | null;
|
||||
authToken: string | null;
|
||||
errors: AppTokenCreate_appTokenCreate_errors[];
|
||||
}
|
||||
|
||||
export interface AppTokenCreate {
|
||||
appTokenCreate: AppTokenCreate_appTokenCreate | null;
|
||||
}
|
||||
|
||||
export interface AppTokenCreateVariables {
|
||||
input: AppTokenInput;
|
||||
}
|
38
src/apps/types/AppTokenDelete.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppErrorCode, PermissionEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppTokenDelete
|
||||
// ====================================================
|
||||
|
||||
export interface AppTokenDelete_appTokenDelete_appToken {
|
||||
__typename: "AppToken";
|
||||
name: string | null;
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface AppTokenDelete_appTokenDelete_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppTokenDelete_appTokenDelete {
|
||||
__typename: "AppTokenDelete";
|
||||
appToken: AppTokenDelete_appTokenDelete_appToken | null;
|
||||
errors: AppTokenDelete_appTokenDelete_errors[];
|
||||
}
|
||||
|
||||
export interface AppTokenDelete {
|
||||
appTokenDelete: AppTokenDelete_appTokenDelete | null;
|
||||
}
|
||||
|
||||
export interface AppTokenDeleteVariables {
|
||||
id: string;
|
||||
}
|
91
src/apps/types/AppUpdate.ts
Normal file
|
@ -0,0 +1,91 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppInput, AppTypeEnum, PermissionEnum, AppErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AppUpdate
|
||||
// ====================================================
|
||||
|
||||
export interface AppUpdate_appUpdate_app_privateMetadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_app_metadata {
|
||||
__typename: "MetadataItem";
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_app_tokens {
|
||||
__typename: "AppToken";
|
||||
authToken: string | null;
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_app_webhooks_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_app_webhooks {
|
||||
__typename: "Webhook";
|
||||
id: string;
|
||||
name: string;
|
||||
isActive: boolean;
|
||||
app: AppUpdate_appUpdate_app_webhooks_app;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_app_permissions {
|
||||
__typename: "Permission";
|
||||
code: PermissionEnum;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_app {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
created: any | null;
|
||||
isActive: boolean | null;
|
||||
type: AppTypeEnum | null;
|
||||
homepageUrl: string | null;
|
||||
appUrl: string | null;
|
||||
configurationUrl: string | null;
|
||||
supportUrl: string | null;
|
||||
version: string | null;
|
||||
accessToken: string | null;
|
||||
privateMetadata: (AppUpdate_appUpdate_app_privateMetadata | null)[];
|
||||
metadata: (AppUpdate_appUpdate_app_metadata | null)[];
|
||||
tokens: (AppUpdate_appUpdate_app_tokens | null)[] | null;
|
||||
webhooks: (AppUpdate_appUpdate_app_webhooks | null)[] | null;
|
||||
permissions: (AppUpdate_appUpdate_app_permissions | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate_errors {
|
||||
__typename: "AppError";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
code: AppErrorCode;
|
||||
permissions: PermissionEnum[] | null;
|
||||
}
|
||||
|
||||
export interface AppUpdate_appUpdate {
|
||||
__typename: "AppUpdate";
|
||||
app: AppUpdate_appUpdate_app | null;
|
||||
errors: AppUpdate_appUpdate_errors[];
|
||||
}
|
||||
|
||||
export interface AppUpdate {
|
||||
appUpdate: AppUpdate_appUpdate | null;
|
||||
}
|
||||
|
||||
export interface AppUpdateVariables {
|
||||
id: string;
|
||||
input: AppInput;
|
||||
}
|
22
src/apps/types/AppsInstallations.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { JobStatusEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: AppsInstallations
|
||||
// ====================================================
|
||||
|
||||
export interface AppsInstallations_appsInstallations {
|
||||
__typename: "AppInstallation";
|
||||
status: JobStatusEnum;
|
||||
message: string | null;
|
||||
appName: string;
|
||||
manifestUrl: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface AppsInstallations {
|
||||
appsInstallations: AppsInstallations_appsInstallations[];
|
||||
}
|
50
src/apps/types/AppsList.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AppSortingInput, AppFilterInput, AppTypeEnum } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL query operation: AppsList
|
||||
// ====================================================
|
||||
|
||||
export interface AppsList_apps_pageInfo {
|
||||
__typename: "PageInfo";
|
||||
hasNextPage: boolean;
|
||||
hasPreviousPage: boolean;
|
||||
startCursor: string | null;
|
||||
endCursor: string | null;
|
||||
}
|
||||
|
||||
export interface AppsList_apps_edges_node {
|
||||
__typename: "App";
|
||||
id: string;
|
||||
name: string | null;
|
||||
isActive: boolean | null;
|
||||
type: AppTypeEnum | null;
|
||||
}
|
||||
|
||||
export interface AppsList_apps_edges {
|
||||
__typename: "AppCountableEdge";
|
||||
node: AppsList_apps_edges_node;
|
||||
}
|
||||
|
||||
export interface AppsList_apps {
|
||||
__typename: "AppCountableConnection";
|
||||
pageInfo: AppsList_apps_pageInfo;
|
||||
totalCount: number | null;
|
||||
edges: AppsList_apps_edges[];
|
||||
}
|
||||
|
||||
export interface AppsList {
|
||||
apps: AppsList_apps | null;
|
||||
}
|
||||
|
||||
export interface AppsListVariables {
|
||||
before?: string | null;
|
||||
after?: string | null;
|
||||
first?: number | null;
|
||||
last?: number | null;
|
||||
sort?: AppSortingInput | null;
|
||||
filter?: AppFilterInput | null;
|
||||
}
|
59
src/apps/urls.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { stringify as stringifyQs } from "qs";
|
||||
import urlJoin from "url-join";
|
||||
|
||||
import { ActiveTab, Dialog, Pagination, SingleAction } from "../types";
|
||||
|
||||
export const MANIFEST_ATTR = "manifestUrl";
|
||||
|
||||
export type AppListUrlDialog = "remove" | "remove-app" | "remove-custom-app";
|
||||
|
||||
export type AppDetailsUrlDialog = "app-activate" | "app-deactivate";
|
||||
|
||||
export type AppListUrlQueryParams = ActiveTab &
|
||||
Dialog<AppListUrlDialog> &
|
||||
SingleAction &
|
||||
Pagination;
|
||||
|
||||
export type AppDetailsUrlQueryParams = Dialog<AppDetailsUrlDialog> &
|
||||
SingleAction;
|
||||
|
||||
export type AppInstallUrlQueryParams = Partial<{ [MANIFEST_ATTR]: string }>;
|
||||
|
||||
export enum AppListUrlSortField {
|
||||
name = "name",
|
||||
active = "active"
|
||||
}
|
||||
|
||||
export type CustomAppUrlDialog =
|
||||
| "create-token"
|
||||
| "remove-webhook"
|
||||
| "remove-token";
|
||||
export type CustomAppUrlQueryParams = Dialog<CustomAppUrlDialog> & SingleAction;
|
||||
|
||||
export const appsSection = "/apps/";
|
||||
export const appsListPath = appsSection;
|
||||
|
||||
export const customAppListPath = "/apps/custom/";
|
||||
|
||||
export const appPath = (id: string) => urlJoin(appsSection, id);
|
||||
export const appSettingsPath = (id: string) =>
|
||||
urlJoin(appsSection, id, "settings");
|
||||
export const customAppPath = (id: string) => urlJoin(customAppListPath, id);
|
||||
export const appInstallPath = urlJoin(appsSection, "install");
|
||||
export const appInstallUrl = appInstallPath;
|
||||
|
||||
export const appUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
|
||||
appPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||
|
||||
export const appSettingsUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
|
||||
urlJoin(appPath(encodeURIComponent(id)), "settings") +
|
||||
"?" +
|
||||
stringifyQs(params);
|
||||
|
||||
export const customAppUrl = (id: string, params?: CustomAppUrlQueryParams) =>
|
||||
customAppPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||
export const customAppAddPath = urlJoin(customAppListPath, "add");
|
||||
export const customAppAddUrl = customAppAddPath;
|
||||
|
||||
export const appsListUrl = (params?: AppListUrlQueryParams) =>
|
||||
appsListPath + "?" + stringifyQs(params);
|
125
src/apps/views/AppDetails/AppDetails.tsx
Normal file
|
@ -0,0 +1,125 @@
|
|||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import getAppErrorMessage from "@saleor/utils/errors/app";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import AppActivateDialog from "../../components/AppActivateDialog";
|
||||
import AppDeactivateDialog from "../../components/AppDeactivateDialog";
|
||||
import AppDetailsPage from "../../components/AppDetailsPage";
|
||||
import {
|
||||
useAppActivateMutation,
|
||||
useAppDeactivateMutation
|
||||
} from "../../mutations";
|
||||
import { useAppDetails } from "../../queries";
|
||||
import {
|
||||
AppDetailsUrlDialog,
|
||||
AppDetailsUrlQueryParams,
|
||||
appSettingsUrl,
|
||||
appsListPath,
|
||||
appUrl
|
||||
} from "../../urls";
|
||||
|
||||
interface AppDetailsProps {
|
||||
id: string;
|
||||
params: AppDetailsUrlQueryParams;
|
||||
}
|
||||
|
||||
export const AppDetails: React.FC<AppDetailsProps> = ({ id, params }) => {
|
||||
const { data, loading, refetch } = useAppDetails({
|
||||
displayLoader: true,
|
||||
variables: { id }
|
||||
});
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
const mutationOpts = { variables: { id } };
|
||||
const [activateApp, activateAppResult] = useAppActivateMutation({
|
||||
onCompleted: data => {
|
||||
const errors = data?.appActivate?.errors;
|
||||
if (errors?.length === 0) {
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "App activated",
|
||||
description: "snackbar text"
|
||||
})
|
||||
});
|
||||
refetch();
|
||||
closeModal();
|
||||
} else {
|
||||
errors.forEach(error =>
|
||||
notify({
|
||||
status: "error",
|
||||
text: getAppErrorMessage(error, intl)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
const [deactivateApp, deactivateAppResult] = useAppDeactivateMutation({
|
||||
onCompleted: data => {
|
||||
const errors = data?.appDeactivate?.errors;
|
||||
if (errors.length === 0) {
|
||||
notify({
|
||||
status: "success",
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "App deactivated",
|
||||
description: "snackbar text"
|
||||
})
|
||||
});
|
||||
refetch();
|
||||
closeModal();
|
||||
} else {
|
||||
errors.forEach(error =>
|
||||
notify({
|
||||
status: "error",
|
||||
text: getAppErrorMessage(error, intl)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const [openModal, closeModal] = createDialogActionHandlers<
|
||||
AppDetailsUrlDialog,
|
||||
AppDetailsUrlQueryParams
|
||||
>(navigate, params => appUrl(id, params), params);
|
||||
|
||||
const handleActivateConfirm = () => {
|
||||
activateApp(mutationOpts);
|
||||
};
|
||||
const handleDeactivateConfirm = () => {
|
||||
deactivateApp(mutationOpts);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppActivateDialog
|
||||
confirmButtonState={activateAppResult.status}
|
||||
name={data?.app.name}
|
||||
onClose={closeModal}
|
||||
onConfirm={handleActivateConfirm}
|
||||
open={params.action === "app-activate"}
|
||||
/>
|
||||
<AppDeactivateDialog
|
||||
confirmButtonState={deactivateAppResult.status}
|
||||
name={data?.app.name}
|
||||
onClose={closeModal}
|
||||
onConfirm={handleDeactivateConfirm}
|
||||
open={params.action === "app-deactivate"}
|
||||
/>
|
||||
<AppDetailsPage
|
||||
data={data?.app}
|
||||
loading={loading}
|
||||
navigateToAppSettings={() => navigate(appSettingsUrl(id))}
|
||||
onAppActivateOpen={() => openModal("app-activate")}
|
||||
onAppDeactivateOpen={() => openModal("app-deactivate")}
|
||||
onBack={() => navigate(appsListPath)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppDetails;
|
2
src/apps/views/AppDetails/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppDetails";
|
||||
export { default } from "./AppDetails";
|
46
src/apps/views/AppDetailsSettings/AppDetailsSettings.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import useShop from "@saleor/hooks/useShop";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import AppDetailsSettingsPage from "../../components/AppDetailsSettingsPage";
|
||||
import { useAppDetails } from "../../queries";
|
||||
import { appsListPath, appUrl } from "../../urls";
|
||||
|
||||
interface AppDetailsSetttingsProps {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const AppDetailsSettings: React.FC<AppDetailsSetttingsProps> = ({
|
||||
id
|
||||
}) => {
|
||||
const shop = useShop();
|
||||
const { data } = useAppDetails({
|
||||
displayLoader: true,
|
||||
variables: { id }
|
||||
});
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<AppDetailsSettingsPage
|
||||
backendHost={shop?.domain.host}
|
||||
data={data?.app}
|
||||
navigateToDashboard={() => navigate(appUrl(id))}
|
||||
onBack={() => navigate(appsListPath)}
|
||||
onError={() =>
|
||||
notify({
|
||||
status: "error",
|
||||
text: intl.formatMessage({
|
||||
defaultMessage: "Failed to fetch app settings",
|
||||
description: "app settings error"
|
||||
})
|
||||
})
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppDetailsSettings;
|
2
src/apps/views/AppDetailsSettings/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export * from "./AppDetailsSettings";
|
||||
export { default } from "./AppDetailsSettings";
|