Browse Source

feat(admin-ui): Implement editing of global settings

Michael Bromley 7 years ago
parent
commit
dc9db9f27a

+ 2 - 4
admin-ui/src/app/common/base-entity-resolver.ts

@@ -31,8 +31,8 @@ export class BaseEntityResolver<T> implements Resolve<Observable<T>> {
 
         if (id === 'create') {
             return of(of(this.emptyEntity));
-        } else if (id) {
-            const stream = this.entityStream(id).pipe(
+        } else {
+            const stream = this.entityStream(id || '').pipe(
                 filter(notNullOrUndefined),
                 shareReplay(1),
             );
@@ -41,8 +41,6 @@ export class BaseEntityResolver<T> implements Resolve<Observable<T>> {
                 take(1),
                 map(() => stream),
             );
-        } else {
-            return {} as any;
         }
     }
 }

+ 192 - 0
admin-ui/src/app/common/language-translation-strings.ts

@@ -0,0 +1,192 @@
+import { _ } from '../core/providers/i18n/mark-for-extraction';
+
+/**
+ * The purpose of this file is to simply mark each available language code (as defined in the
+ * LanguageCode GraphQL enum) with the `mark-for-extraction` function, so that when running
+ * the "extract-translations" script, the language translation tokens will be extracted.
+ */
+
+_('lang.aa');
+_('lang.ab');
+_('lang.af');
+_('lang.ak');
+_('lang.sq');
+_('lang.am');
+_('lang.ar');
+_('lang.an');
+_('lang.hy');
+_('lang.as');
+_('lang.av');
+_('lang.ae');
+_('lang.ay');
+_('lang.az');
+_('lang.ba');
+_('lang.bm');
+_('lang.eu');
+_('lang.be');
+_('lang.bn');
+_('lang.bh');
+_('lang.bi');
+_('lang.bs');
+_('lang.br');
+_('lang.bg');
+_('lang.my');
+_('lang.ca');
+_('lang.ch');
+_('lang.ce');
+_('lang.zh');
+_('lang.cu');
+_('lang.cv');
+_('lang.kw');
+_('lang.co');
+_('lang.cr');
+_('lang.cs');
+_('lang.da');
+_('lang.dv');
+_('lang.nl');
+_('lang.dz');
+_('lang.en');
+_('lang.eo');
+_('lang.et');
+_('lang.ee');
+_('lang.fo');
+_('lang.fj');
+_('lang.fi');
+_('lang.fr');
+_('lang.fy');
+_('lang.ff');
+_('lang.ka');
+_('lang.de');
+_('lang.gd');
+_('lang.ga');
+_('lang.gl');
+_('lang.gv');
+_('lang.el');
+_('lang.gn');
+_('lang.gu');
+_('lang.ht');
+_('lang.ha');
+_('lang.he');
+_('lang.hz');
+_('lang.hi');
+_('lang.ho');
+_('lang.hr');
+_('lang.hu');
+_('lang.ig');
+_('lang.is');
+_('lang.io');
+_('lang.ii');
+_('lang.iu');
+_('lang.ie');
+_('lang.ia');
+_('lang.id');
+_('lang.ik');
+_('lang.it');
+_('lang.jv');
+_('lang.ja');
+_('lang.kl');
+_('lang.kn');
+_('lang.ks');
+_('lang.kr');
+_('lang.kk');
+_('lang.km');
+_('lang.ki');
+_('lang.rw');
+_('lang.ky');
+_('lang.kv');
+_('lang.kg');
+_('lang.ko');
+_('lang.kj');
+_('lang.ku');
+_('lang.lo');
+_('lang.la');
+_('lang.lv');
+_('lang.li');
+_('lang.ln');
+_('lang.lt');
+_('lang.lb');
+_('lang.lu');
+_('lang.lg');
+_('lang.mk');
+_('lang.mh');
+_('lang.ml');
+_('lang.mi');
+_('lang.mr');
+_('lang.ms');
+_('lang.mg');
+_('lang.mt');
+_('lang.mn');
+_('lang.na');
+_('lang.nv');
+_('lang.nr');
+_('lang.nd');
+_('lang.ng');
+_('lang.ne');
+_('lang.nn');
+_('lang.nb');
+_('lang.no');
+_('lang.ny');
+_('lang.oc');
+_('lang.oj');
+_('lang.or');
+_('lang.om');
+_('lang.os');
+_('lang.pa');
+_('lang.fa');
+_('lang.pi');
+_('lang.pl');
+_('lang.pt');
+_('lang.ps');
+_('lang.qu');
+_('lang.rm');
+_('lang.ro');
+_('lang.rn');
+_('lang.ru');
+_('lang.sg');
+_('lang.sa');
+_('lang.si');
+_('lang.sk');
+_('lang.sl');
+_('lang.se');
+_('lang.sm');
+_('lang.sn');
+_('lang.sd');
+_('lang.so');
+_('lang.st');
+_('lang.es');
+_('lang.sc');
+_('lang.sr');
+_('lang.ss');
+_('lang.su');
+_('lang.sw');
+_('lang.sv');
+_('lang.ty');
+_('lang.ta');
+_('lang.tt');
+_('lang.te');
+_('lang.tg');
+_('lang.tl');
+_('lang.th');
+_('lang.bo');
+_('lang.ti');
+_('lang.to');
+_('lang.tn');
+_('lang.ts');
+_('lang.tk');
+_('lang.tr');
+_('lang.tw');
+_('lang.ug');
+_('lang.uk');
+_('lang.ur');
+_('lang.uz');
+_('lang.ve');
+_('lang.vi');
+_('lang.vo');
+_('lang.cy');
+_('lang.wa');
+_('lang.wo');
+_('lang.xh');
+_('lang.yi');
+_('lang.yo');
+_('lang.za');
+_('lang.zu');

+ 10 - 0
admin-ui/src/app/core/components/main-nav/main-nav.component.html

@@ -139,6 +139,16 @@
                         {{ 'nav.countries' | translate }}
                     </a>
                 </li>
+                <li>
+                    <a
+                        class="nav-link"
+                        [routerLink]="['/settings', 'global-settings']"
+                        routerLinkActive="active"
+                    >
+                        <clr-icon shape="cog" size="20"></clr-icon>
+                        {{ 'nav.global-settings' | translate }}
+                    </a>
+                </li>
             </ul>
         </section>
     </section>

+ 2 - 2
admin-ui/src/app/customer/components/customer-detail/customer-detail.component.html

@@ -57,11 +57,11 @@
         </vdr-form-field>
 
         <section formGroupName="customFields" *ngIf="customFields.length">
-            <label>{{ 'common.custom-fields' }}</label>
+            <label>{{ 'common.custom-fields' | translate }}</label>
             <ng-container *ngFor="let customField of customFields">
                 <vdr-custom-field-control
                     *ngIf="customFieldIsSet(customField.name)"
-                    [customFieldsFormGroup]="detailForm.get(['facet', 'customFields'])"
+                    [customFieldsFormGroup]="detailForm.get('customFields')"
                     [customField]="customField"
                 ></vdr-custom-field-control>
             </ng-container>

+ 24 - 0
admin-ui/src/app/data/definitions/settings-definitions.ts

@@ -334,3 +334,27 @@ export const UPDATE_PAYMENT_METHOD = gql`
     }
     ${PAYMENT_METHOD_FRAGMENT}
 `;
+
+export const GLOBAL_SETTINGS_FRAGMENT = gql`
+    fragment GlobalSettings on GlobalSettings {
+        availableLanguages
+    }
+`;
+
+export const GET_GLOBAL_SETTINGS = gql`
+    query GetGlobalSettings {
+        globalSettings {
+            ...GlobalSettings
+        }
+    }
+    ${GLOBAL_SETTINGS_FRAGMENT}
+`;
+
+export const UPDATE_GLOBAL_SETTINGS = gql`
+    mutation UpdateGlobalSettings($input: UpdateGlobalSettingsInput!) {
+        updateGlobalSettings(input: $input) {
+            ...GlobalSettings
+        }
+    }
+    ${GLOBAL_SETTINGS_FRAGMENT}
+`;

+ 18 - 0
admin-ui/src/app/data/providers/settings-data.service.ts

@@ -15,6 +15,7 @@ import {
     GetChannels,
     GetCountry,
     GetCountryList,
+    GetGlobalSettings,
     GetPaymentMethod,
     GetPaymentMethodList,
     GetTaxCategories,
@@ -28,6 +29,8 @@ import {
     UpdateChannelInput,
     UpdateCountry,
     UpdateCountryInput,
+    UpdateGlobalSettings,
+    UpdateGlobalSettingsInput,
     UpdatePaymentMethod,
     UpdatePaymentMethodInput,
     UpdateTaxCategory,
@@ -51,6 +54,7 @@ import {
     GET_CHANNELS,
     GET_COUNTRY,
     GET_COUNTRY_LIST,
+    GET_GLOBAL_SETTINGS,
     GET_PAYMENT_METHOD,
     GET_PAYMENT_METHOD_LIST,
     GET_TAX_CATEGORIES,
@@ -61,6 +65,7 @@ import {
     REMOVE_MEMBERS_FROM_ZONE,
     UPDATE_CHANNEL,
     UPDATE_COUNTRY,
+    UPDATE_GLOBAL_SETTINGS,
     UPDATE_PAYMENT_METHOD,
     UPDATE_TAX_CATEGORY,
     UPDATE_TAX_RATE,
@@ -249,4 +254,17 @@ export class SettingsDataService {
             },
         );
     }
+
+    getGlobalSettings() {
+        return this.baseDataService.query<GetGlobalSettings.Query>(GET_GLOBAL_SETTINGS);
+    }
+
+    updateGlobalSettings(input: UpdateGlobalSettingsInput) {
+        return this.baseDataService.mutate<UpdateGlobalSettings.Mutation, UpdateGlobalSettings.Variables>(
+            UPDATE_GLOBAL_SETTINGS,
+            {
+                input,
+            },
+        );
+    }
 }

+ 48 - 0
admin-ui/src/app/settings/components/global-settings/global-settings.component.html

@@ -0,0 +1,48 @@
+<vdr-action-bar>
+    <vdr-ab-right>
+        <button
+            class="btn btn-primary"
+            (click)="save()"
+            [disabled]="detailForm.invalid || detailForm.pristine"
+        >
+            {{ 'common.update' | translate }}
+        </button>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<form class="form" [formGroup]="detailForm">
+    <section class="form-block">
+        <vdr-form-field [label]="'common.available-languages' | translate" for="availableLanguages">
+            <ng-select
+                [items]="languageCodes"
+                [addTag]="false"
+                [hideSelected]="true"
+                multiple="true"
+                appendTo="body"
+                formControlName="availableLanguages"
+            >
+                <ng-template ng-label-tmp let-item="item" let-clear="clear">
+                    <span class="ng-value-icon left" (click)="clear.call(null, item)" aria-hidden="true">
+                        ×
+                    </span>
+                    <span class="ng-value-label">
+                        {{ 'lang.' + item | translate }} ({{ item | uppercase }})
+                    </span>
+                </ng-template>
+                <ng-template ng-option-tmp let-item="item">
+                    {{ 'lang.' + item | translate }} ({{ item | uppercase }})
+                </ng-template>
+            </ng-select>
+        </vdr-form-field>
+    </section>
+    <section formGroupName="customFields" *ngIf="customFields.length">
+        <label>{{ 'common.custom-fields' | translate }}</label>
+        <ng-container *ngFor="let customField of customFields">
+            <vdr-custom-field-control
+                *ngIf="customFieldIsSet(customField.name)"
+                [customFieldsFormGroup]="detailForm.get('customFields')"
+                [customField]="customField"
+            ></vdr-custom-field-control>
+        </ng-container>
+    </section>
+</form>

+ 13 - 0
admin-ui/src/app/settings/components/global-settings/global-settings.component.scss

@@ -0,0 +1,13 @@
+@import "variables";
+
+::ng-deep ng-select {
+    .ng-value > span {
+        margin: 0 !important;
+    }
+    .ng-arrow-wrapper .ng-arrow {
+        margin: 0 !important;
+    }
+    .ng-select-container > span {
+        margin: 0 !important;
+    }
+}

+ 87 - 0
admin-ui/src/app/settings/components/global-settings/global-settings.component.ts

@@ -0,0 +1,87 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { GlobalSettings, LanguageCode } from 'shared/generated-types';
+import { CustomFieldConfig } from 'shared/shared-types';
+
+import { BaseDetailComponent } from '../../../common/base-detail.component';
+import { _ } from '../../../core/providers/i18n/mark-for-extraction';
+import { NotificationService } from '../../../core/providers/notification/notification.service';
+import { DataService } from '../../../data/providers/data.service';
+import { ServerConfigService } from '../../../data/server-config';
+
+@Component({
+    selector: 'vdr-global-settings',
+    templateUrl: './global-settings.component.html',
+    styleUrls: ['./global-settings.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class GlobalSettingsComponent extends BaseDetailComponent<GlobalSettings> implements OnInit {
+    detailForm: FormGroup;
+    customFields: CustomFieldConfig[];
+    languageCodes = Object.values(LanguageCode);
+
+    constructor(
+        router: Router,
+        route: ActivatedRoute,
+        serverConfigService: ServerConfigService,
+        private changeDetector: ChangeDetectorRef,
+        private dataService: DataService,
+        private formBuilder: FormBuilder,
+        private notificationService: NotificationService,
+    ) {
+        super(route, router, serverConfigService);
+        this.customFields = this.getCustomFieldConfig('GlobalSettings');
+        this.detailForm = this.formBuilder.group({
+            availableLanguages: [''],
+            customFields: this.formBuilder.group(
+                this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),
+            ),
+        });
+    }
+
+    ngOnInit(): void {
+        this.init();
+    }
+
+    customFieldIsSet(name: string): boolean {
+        return !!this.detailForm.get(['customFields', name]);
+    }
+
+    save() {
+        if (!this.detailForm.dirty) {
+            return;
+        }
+
+        this.dataService.settings.updateGlobalSettings(this.detailForm.value).subscribe(
+            () => {
+                this.detailForm.markAsPristine();
+                this.changeDetector.markForCheck();
+                this.notificationService.success(_('common.notify-update-success'), { entity: 'Settings' });
+            },
+            err => {
+                this.notificationService.error(_('common.notify-update-error'), {
+                    entity: 'Settings',
+                });
+            },
+        );
+    }
+
+    protected setFormValues(entity: GlobalSettings, languageCode: LanguageCode): void {
+        this.detailForm.patchValue({
+            availableLanguages: entity.availableLanguages,
+        });
+        if (this.customFields.length) {
+            const customFieldsGroup = this.detailForm.get('customFields') as FormGroup;
+
+            for (const fieldDef of this.customFields) {
+                const key = fieldDef.name;
+                const value = (entity as any).customFields[key];
+                const control = customFieldsGroup.get(key);
+                if (control) {
+                    control.patchValue(value);
+                }
+            }
+        }
+    }
+}

+ 19 - 0
admin-ui/src/app/settings/providers/routing/global-settings-resolver.ts

@@ -0,0 +1,19 @@
+import { Injectable } from '@angular/core';
+import { GetGlobalSettings } from 'shared/generated-types';
+
+import { BaseEntityResolver } from '../../../common/base-entity-resolver';
+import { DataService } from '../../../data/providers/data.service';
+
+/**
+ * Resolves the global settings.
+ */
+@Injectable()
+export class GlobalSettingsResolver extends BaseEntityResolver<GetGlobalSettings.GlobalSettings> {
+    constructor(private dataService: DataService) {
+        super(
+            // we will never be creating a new GlobalSettings entity, so this part is not used.
+            {} as any,
+            () => this.dataService.settings.getGlobalSettings().mapStream(data => data.globalSettings),
+        );
+    }
+}

+ 4 - 0
admin-ui/src/app/settings/settings.module.ts

@@ -9,6 +9,7 @@ import { ChannelDetailComponent } from './components/channel-detail/channel-deta
 import { ChannelListComponent } from './components/channel-list/channel-list.component';
 import { CountryDetailComponent } from './components/country-detail/country-detail.component';
 import { CountryListComponent } from './components/country-list/country-list.component';
+import { GlobalSettingsComponent } from './components/global-settings/global-settings.component';
 import { PaymentMethodDetailComponent } from './components/payment-method-detail/payment-method-detail.component';
 import { PaymentMethodListComponent } from './components/payment-method-list/payment-method-list.component';
 import { PermissionGridComponent } from './components/permission-grid/permission-grid.component';
@@ -24,6 +25,7 @@ import { ZoneSelectorDialogComponent } from './components/zone-selector-dialog/z
 import { AdministratorResolver } from './providers/routing/administrator-resolver';
 import { ChannelResolver } from './providers/routing/channel-resolver';
 import { CountryResolver } from './providers/routing/country-resolver';
+import { GlobalSettingsResolver } from './providers/routing/global-settings-resolver';
 import { PaymentMethodResolver } from './providers/routing/payment-method-resolver';
 import { RoleResolver } from './providers/routing/role-resolver';
 import { ShippingMethodResolver } from './providers/routing/shipping-method-resolver';
@@ -52,6 +54,7 @@ import { settingsRoutes } from './settings.routes';
         ShippingMethodDetailComponent,
         PaymentMethodListComponent,
         PaymentMethodDetailComponent,
+        GlobalSettingsComponent,
     ],
     entryComponents: [ZoneSelectorDialogComponent],
     providers: [
@@ -63,6 +66,7 @@ import { settingsRoutes } from './settings.routes';
         ChannelResolver,
         ShippingMethodResolver,
         PaymentMethodResolver,
+        GlobalSettingsResolver,
     ],
 })
 export class SettingsModule {}

+ 11 - 0
admin-ui/src/app/settings/settings.routes.ts

@@ -20,6 +20,7 @@ import { ChannelDetailComponent } from './components/channel-detail/channel-deta
 import { ChannelListComponent } from './components/channel-list/channel-list.component';
 import { CountryDetailComponent } from './components/country-detail/country-detail.component';
 import { CountryListComponent } from './components/country-list/country-list.component';
+import { GlobalSettingsComponent } from './components/global-settings/global-settings.component';
 import { PaymentMethodDetailComponent } from './components/payment-method-detail/payment-method-detail.component';
 import { PaymentMethodListComponent } from './components/payment-method-list/payment-method-list.component';
 import { RoleDetailComponent } from './components/role-detail/role-detail.component';
@@ -33,6 +34,7 @@ import { TaxRateListComponent } from './components/tax-rate-list/tax-rate-list.c
 import { AdministratorResolver } from './providers/routing/administrator-resolver';
 import { ChannelResolver } from './providers/routing/channel-resolver';
 import { CountryResolver } from './providers/routing/country-resolver';
+import { GlobalSettingsResolver } from './providers/routing/global-settings-resolver';
 import { PaymentMethodResolver } from './providers/routing/payment-method-resolver';
 import { RoleResolver } from './providers/routing/role-resolver';
 import { ShippingMethodResolver } from './providers/routing/shipping-method-resolver';
@@ -162,6 +164,15 @@ export const settingsRoutes: Route[] = [
             breadcrumb: paymentMethodBreadcrumb,
         },
     },
+    {
+        path: 'global-settings',
+        component: GlobalSettingsComponent,
+        resolve: createResolveData(GlobalSettingsResolver),
+        canDeactivate: [CanDeactivateDetailGuard],
+        data: {
+            breadcrumb: _('breadcrumb.global-settings'),
+        },
+    },
 ];
 
 export function administratorBreadcrumb(data: any, params: any) {

+ 189 - 0
admin-ui/src/i18n-messages/en.json

@@ -11,6 +11,7 @@
     "customers": "Customers",
     "dashboard": "Dashboard",
     "facets": "Facets",
+    "global-settings": "Global settings",
     "orders": "Orders",
     "payment-methods": "Payment methods",
     "products": "Products",
@@ -77,6 +78,7 @@
   },
   "common": {
     "ID": "ID",
+    "available-languages": "Available languages",
     "back": "Back",
     "cancel": "Cancel",
     "cancel-navigation": "Cancel navigation",
@@ -135,6 +137,192 @@
     "facet-value-form-values-do-not-match": "The number of values in the facet form does not match the actual number of values",
     "product-variant-form-values-do-not-match": "The number of variants in the product form does not match the actual number of variants"
   },
+  "lang": {
+    "aa": "Afar",
+    "ab": "Abkhazian",
+    "ae": "Avestan",
+    "af": "Afrikaans",
+    "ak": "Akan",
+    "am": "Amharic",
+    "an": "Aragonese",
+    "ar": "Arabic",
+    "as": "Assamese",
+    "av": "Avaric",
+    "ay": "Aymara",
+    "az": "Azerbaijani",
+    "ba": "Bashkir",
+    "be": "Belarusian",
+    "bg": "Bulgarian",
+    "bh": "Bihari languages",
+    "bi": "Bislama",
+    "bm": "Bambara",
+    "bn": "Bengali",
+    "bo": "Tibetan",
+    "br": "Breton",
+    "bs": "Bosnian",
+    "ca": "Catalan; Valencian",
+    "ce": "Chechen",
+    "ch": "Chamorro",
+    "co": "Corsican",
+    "cr": "Cree",
+    "cs": "Czech",
+    "cu": "Church Slavic",
+    "cv": "Chuvash",
+    "cy": "Welsh",
+    "da": "Danish",
+    "de": "German",
+    "dv": "Divehi; Dhivehi; Maldivian",
+    "dz": "Dzongkha",
+    "ee": "Ewe",
+    "el": "Greek, Modern (1453-)",
+    "en": "English",
+    "eo": "Esperanto",
+    "es": "Spanish; Castilian",
+    "et": "Estonian",
+    "eu": "Basque",
+    "fa": "Persian",
+    "ff": "Fulah",
+    "fi": "Finnish",
+    "fj": "Fijian",
+    "fo": "Faroese",
+    "fr": "French",
+    "fy": "Western Frisian",
+    "ga": "Irish",
+    "gd": "Gaelic; Scottish Gaelic",
+    "gl": "Galician",
+    "gn": "Guarani",
+    "gu": "Gujarati",
+    "gv": "Manx",
+    "ha": "Hausa",
+    "he": "Hebrew",
+    "hi": "Hindi",
+    "ho": "Hiri Motu",
+    "hr": "Croatian",
+    "ht": "Haitian; Haitian Creole",
+    "hu": "Hungarian",
+    "hy": "Armenian",
+    "hz": "Herero",
+    "ia": "Interlingua",
+    "id": "Indonesian",
+    "ie": "Interlingue; Occidental",
+    "ig": "Igbo",
+    "ii": "Sichuan Yi; Nuosu",
+    "ik": "Inupiaq",
+    "io": "Ido",
+    "is": "Icelandic",
+    "it": "Italian",
+    "iu": "Inuktitut",
+    "ja": "Japanese",
+    "jv": "Javanese",
+    "ka": "Georgian",
+    "kg": "Kongo",
+    "ki": "Kikuyu; Gikuyu",
+    "kj": "Kuanyama; Kwanyama",
+    "kk": "Kazakh",
+    "kl": "Kalaallisut; Greenlandic",
+    "km": "Central Khmer",
+    "kn": "Kannada",
+    "ko": "Korean",
+    "kr": "Kanuri",
+    "ks": "Kashmiri",
+    "ku": "Kurdish",
+    "kv": "Komi",
+    "kw": "Cornish",
+    "ky": "Kirghiz; Kyrgyz",
+    "la": "Latin",
+    "lb": "Luxembourgish; Letzeburgesch",
+    "lg": "Ganda",
+    "li": "Limburgan; Limburger; Limburgish",
+    "ln": "Lingala",
+    "lo": "Lao",
+    "lt": "Lithuanian",
+    "lu": "Luba-Katanga",
+    "lv": "Latvian",
+    "mg": "Malagasy",
+    "mh": "Marshallese",
+    "mi": "Maori",
+    "mk": "Macedonian",
+    "ml": "Malayalam",
+    "mn": "Mongolian",
+    "mr": "Marathi",
+    "ms": "Malay",
+    "mt": "Maltese",
+    "my": "Burmese",
+    "na": "Nauru",
+    "nb": "Bokmål, Norwegian; Norwegian Bokmål",
+    "nd": "Ndebele, North; North Ndebele",
+    "ne": "Nepali",
+    "ng": "Ndonga",
+    "nl": "Dutch; Flemish",
+    "nn": "Norwegian Nynorsk; Nynorsk, Norwegian",
+    "no": "Norwegian",
+    "nr": "Ndebele, South; South Ndebele",
+    "nv": "Navajo; Navaho",
+    "ny": "Chichewa; Chewa; Nyanja",
+    "oc": "Occitan (post 1500); Provençal",
+    "oj": "Ojibwa",
+    "om": "Oromo",
+    "or": "Oriya",
+    "os": "Ossetian; Ossetic",
+    "pa": "Panjabi; Punjabi",
+    "pi": "Pali",
+    "pl": "Polish",
+    "ps": "Pushto; Pashto",
+    "pt": "Portuguese",
+    "qu": "Quechua",
+    "rm": "Romansh",
+    "rn": "Rundi",
+    "ro": "Romanian; Moldavian; Moldovan",
+    "ru": "Russian",
+    "rw": "Kinyarwanda",
+    "sa": "Sanskrit",
+    "sc": "Sardinian",
+    "sd": "Sindhi",
+    "se": "Northern Sami",
+    "sg": "Sango",
+    "si": "Sinhala; Sinhalese",
+    "sk": "Slovak",
+    "sl": "Slovenian",
+    "sm": "Samoan",
+    "sn": "Shona",
+    "so": "Somali",
+    "sq": "Albanian",
+    "sr": "Serbian",
+    "ss": "Swati",
+    "st": "Sotho, Southern",
+    "su": "Sundanese",
+    "sv": "Swedish",
+    "sw": "Swahili",
+    "ta": "Tamil",
+    "te": "Telugu",
+    "tg": "Tajik",
+    "th": "Thai",
+    "ti": "Tigrinya",
+    "tk": "Turkmen",
+    "tl": "Tagalog",
+    "tn": "Tswana",
+    "to": "Tonga (Tonga Islands)",
+    "tr": "Turkish",
+    "ts": "Tsonga",
+    "tt": "Tatar",
+    "tw": "Twi",
+    "ty": "Tahitian",
+    "ug": "Uighur; Uyghur",
+    "uk": "Ukrainian",
+    "ur": "Urdu",
+    "uz": "Uzbek",
+    "ve": "Venda",
+    "vi": "Vietnamese",
+    "vo": "Volapük",
+    "wa": "Walloon",
+    "wo": "Wolof",
+    "xh": "Xhosa",
+    "yi": "Yiddish",
+    "yo": "Yoruba",
+    "za": "Zhuang; Chuang",
+    "zh": "Chinese",
+    "zu": "Zulu"
+  },
   "marketing": {
     "actions": "Actions",
     "add-action": "Add action",
@@ -151,6 +339,7 @@
     "countries": "Countries",
     "customers": "Customers",
     "facets": "Facets",
+    "global-settings": "Global settings",
     "marketing": "Marketing",
     "orders": "Orders",
     "payment-methods": "Payment methods",

+ 30 - 0
shared/generated-types.ts

@@ -6386,6 +6386,36 @@ export namespace UpdatePaymentMethod {
     export type UpdatePaymentMethod = PaymentMethod.Fragment;
 }
 
+export namespace GetGlobalSettings {
+    export type Variables = {};
+
+    export type Query = {
+        __typename?: 'Query';
+        globalSettings: GlobalSettings;
+    };
+
+    export type GlobalSettings = {
+        __typename?: 'GlobalSettings';
+        availableLanguages: LanguageCode[];
+    };
+}
+
+export namespace UpdateGlobalSettings {
+    export type Variables = {
+        input: UpdateGlobalSettingsInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        updateGlobalSettings: UpdateGlobalSettings;
+    };
+
+    export type UpdateGlobalSettings = {
+        __typename?: 'GlobalSettings';
+        availableLanguages: LanguageCode[];
+    };
+}
+
 export namespace GetShippingMethodList {
     export type Variables = {
         options?: ShippingMethodListOptions | null;