From 01f54aeb52cd2391cca8a544a6e5901cf5e39d16 Mon Sep 17 00:00:00 2001 From: Ryan Sheppard Date: Sun, 21 Jul 2024 08:29:46 -0500 Subject: [PATCH 1/6] Add URL column to CSV export for items (#141) * feat: Add URL column to CSV export for items Enhanced the CSV export functionality to include a URL field for each item. This change required updating the export logic to generate and include item URLs based on the request's referer header. * chore: add URL configuration to V1Controller for dynamic URL handling in item export --- backend/app/api/handlers/v1/controller.go | 7 +++++ backend/app/api/handlers/v1/v1_ctrl_items.go | 26 ++++++++++++++++++- backend/app/api/routes.go | 2 ++ .../core/services/reporting/io_row.go | 1 + .../core/services/reporting/io_sheet.go | 13 +++++++++- .../internal/core/services/service_items.go | 4 +-- 6 files changed, 49 insertions(+), 4 deletions(-) diff --git a/backend/app/api/handlers/v1/controller.go b/backend/app/api/handlers/v1/controller.go index 33fdd631..135b1446 100644 --- a/backend/app/api/handlers/v1/controller.go +++ b/backend/app/api/handlers/v1/controller.go @@ -57,6 +57,12 @@ func WithSecureCookies(secure bool) func(*V1Controller) { } } +func WithURL(url string) func(*V1Controller) { + return func(ctrl *V1Controller) { + ctrl.url = url + } +} + type V1Controller struct { cookieSecure bool repo *repo.AllRepos @@ -65,6 +71,7 @@ type V1Controller struct { isDemo bool allowRegistration bool bus *eventbus.EventBus + url string } type ( diff --git a/backend/app/api/handlers/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go index a978d031..1eddc0fc 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items.go @@ -6,6 +6,7 @@ import ( "errors" "math/big" "net/http" + "net/url" "strings" "github.com/google/uuid" @@ -333,7 +334,7 @@ func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - csvData, err := ctrl.svc.Items.ExportCSV(r.Context(), ctx.GID) + csvData, err := ctrl.svc.Items.ExportCSV(r.Context(), ctx.GID, getHBURL(r.Header.Get("Referer"), ctrl.url)) if err != nil { log.Err(err).Msg("failed to export items") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -347,3 +348,26 @@ func (ctrl *V1Controller) HandleItemsExport() errchain.HandlerFunc { return writer.WriteAll(csvData) } } + +func getHBURL(refererHeader, fallback string) (hbURL string) { + hbURL = refererHeader + if hbURL == "" { + hbURL = fallback + } + + return stripPathFromURL(hbURL) +} + +// stripPathFromURL removes the path from a URL. +// ex. https://example.com/tools -> https://example.com +func stripPathFromURL(rawURL string) string { + parsedURL, err := url.Parse(rawURL) + if err != nil { + log.Err(err).Msg("failed to parse URL") + return "" + } + + strippedURL := url.URL{Scheme: parsedURL.Scheme, Host: parsedURL.Host} + + return strippedURL.String() +} diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index 551582e0..faca9906 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -3,6 +3,7 @@ package main import ( "embed" "errors" + "fmt" "io" "mime" "net/http" @@ -54,6 +55,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), v1.WithRegistration(a.conf.Options.AllowRegistration), v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode + v1.WithURL(fmt.Sprintf("%s:%s", a.conf.Web.Host, a.conf.Web.Port)), ) r.Route(prefix+"/v1", func(r chi.Router) { diff --git a/backend/internal/core/services/reporting/io_row.go b/backend/internal/core/services/reporting/io_row.go index ca3c8010..1e3415b4 100644 --- a/backend/internal/core/services/reporting/io_row.go +++ b/backend/internal/core/services/reporting/io_row.go @@ -18,6 +18,7 @@ type ExportCSVRow struct { LabelStr LabelString `csv:"HB.labels"` AssetID repo.AssetID `csv:"HB.asset_id"` Archived bool `csv:"HB.archived"` + URL string `csv:"HB.url"` Name string `csv:"HB.name"` Quantity int `csv:"HB.quantity"` diff --git a/backend/internal/core/services/reporting/io_sheet.go b/backend/internal/core/services/reporting/io_sheet.go index 08676bd0..21d07d1b 100644 --- a/backend/internal/core/services/reporting/io_sheet.go +++ b/backend/internal/core/services/reporting/io_sheet.go @@ -153,7 +153,7 @@ func (s *IOSheet) Read(data io.Reader) error { } // ReadItems writes the sheet to a writer. -func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos) error { +func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid.UUID, repos *repo.AllRepos, hbURL string) error { s.Rows = make([]ExportCSVRow, len(items)) extraHeaders := map[string]struct{}{} @@ -178,6 +178,8 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid. labelString[i] = l.Name } + url := generateItemURL(item, hbURL) + customFields := make([]ExportItemFields, len(item.Fields)) for i, f := range item.Fields { @@ -201,6 +203,7 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid. Description: item.Description, Insured: item.Insured, Archived: item.Archived, + URL: url, PurchasePrice: item.PurchasePrice, PurchaseFrom: item.PurchaseFrom, @@ -252,6 +255,14 @@ func (s *IOSheet) ReadItems(ctx context.Context, items []repo.ItemOut, GID uuid. return nil } +func generateItemURL(item repo.ItemOut, d string) string { + url := "" + if item.ID != uuid.Nil { + url = fmt.Sprintf("%s/item/%s", d, item.ID.String()) + } + return url +} + // CSV writes the current sheet to a 2d array, for compatibility with TSV/CSV files. func (s *IOSheet) CSV() ([][]string, error) { memcsv := make([][]string, len(s.Rows)+1) diff --git a/backend/internal/core/services/service_items.go b/backend/internal/core/services/service_items.go index d6f1896c..88b7e28a 100644 --- a/backend/internal/core/services/service_items.go +++ b/backend/internal/core/services/service_items.go @@ -329,7 +329,7 @@ func (svc *ItemService) CsvImport(ctx context.Context, GID uuid.UUID, data io.Re return finished, nil } -func (svc *ItemService) ExportCSV(ctx context.Context, GID uuid.UUID) ([][]string, error) { +func (svc *ItemService) ExportCSV(ctx context.Context, GID uuid.UUID, hbURL string) ([][]string, error) { items, err := svc.repo.Items.GetAll(ctx, GID) if err != nil { return nil, err @@ -337,7 +337,7 @@ func (svc *ItemService) ExportCSV(ctx context.Context, GID uuid.UUID) ([][]strin sheet := reporting.IOSheet{} - err = sheet.ReadItems(ctx, items, GID, svc.repo) + err = sheet.ReadItems(ctx, items, GID, svc.repo, hbURL) if err != nil { return nil, err } From c9f31ef93421df26f30802b51af7ed57e30e2ca4 Mon Sep 17 00:00:00 2001 From: Ryan Sheppard Date: Sun, 21 Jul 2024 08:30:03 -0500 Subject: [PATCH 2/6] Enable Sorting on Search By Created and Updated At (#140) - Required updating query value to use first.value to set the value of the initial sort - Ordering starts with name but can be changed to createdAt or updatedAt by the user --- frontend/composables/use-route-params.ts | 2 +- frontend/pages/items.vue | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/composables/use-route-params.ts b/frontend/composables/use-route-params.ts index e0464639..dfd16f1c 100644 --- a/frontend/composables/use-route-params.ts +++ b/frontend/composables/use-route-params.ts @@ -32,7 +32,7 @@ export function useRouteQuery(q: string, def: any): WritableComputedRef { case "string": return computed({ get: () => { - const qv = route.query[q]; + const qv = first.value; if (Array.isArray(qv)) { return qv[0]; } diff --git a/frontend/pages/items.vue b/frontend/pages/items.vue index 2213975b..734b1abb 100644 --- a/frontend/pages/items.vue +++ b/frontend/pages/items.vue @@ -40,6 +40,7 @@ const includeArchived = useRouteQuery("archived", false); const fieldSelector = useRouteQuery("fieldSelector", false); const negateLabels = useRouteQuery("negateLabels", false); + const orderBy = useRouteQuery("orderBy", "name"); const totalPages = computed(() => Math.ceil(total.value / pageSize.value)); const hasNext = computed(() => page.value * pageSize.value < total.value); @@ -169,6 +170,12 @@ } }); + watch(orderBy, (newV, oldV) => { + if (newV !== oldV) { + search(); + } + }); + async function fetchValues(field: string): Promise { if (fieldValuesCache.value[field]) { return fieldValuesCache.value[field]; @@ -201,6 +208,7 @@ pageSize: pageSize.value, includeArchived: includeArchived.value ? "true" : "false", negateLabels: negateLabels.value ? "true" : "false", + orderBy: orderBy.value, }, }); } @@ -231,6 +239,7 @@ includeArchived: includeArchived.value, page: page.value, pageSize: pageSize.value, + orderBy: orderBy.value, fields, }); @@ -278,6 +287,7 @@ archived: includeArchived.value ? "true" : "false", fieldSelector: fieldSelector.value ? "true" : "false", negateLabels: negateLabels.value ? "true" : "false", + orderBy: orderBy.value, pageSize: pageSize.value, page: page.value, q: query.value, @@ -311,6 +321,7 @@ fieldSelector: "false", pageSize: 10, page: 1, + orderBy: "name", q: "", loc: [], lab: [], @@ -373,6 +384,14 @@ Negate selected labels +
Reset Search From 42f3c88396f18866ab38dcd275407c8b7060bb79 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 10:39:47 -0400 Subject: [PATCH 3/6] Update currencies.json (#143) Co-authored-by: github-actions[bot] Co-authored-by: Matt Kilgore --- .../internal/core/currencies/currencies.json | 2578 ++++++++--------- 1 file changed, 1289 insertions(+), 1289 deletions(-) diff --git a/backend/internal/core/currencies/currencies.json b/backend/internal/core/currencies/currencies.json index 7901a869..1af92cc1 100644 --- a/backend/internal/core/currencies/currencies.json +++ b/backend/internal/core/currencies/currencies.json @@ -1,4 +1,40 @@ [ + { + "code": "SHP", + "local": "South Georgia", + "symbol": "£", + "name": "Saint Helena pound" + }, + { + "code": "XCD", + "local": "Grenada", + "symbol": "$", + "name": "Eastern Caribbean dollar" + }, + { + "code": "CHF", + "local": "Switzerland", + "symbol": "Fr.", + "name": "Swiss franc" + }, + { + "code": "SLL", + "local": "Sierra Leone", + "symbol": "Le", + "name": "Sierra Leonean leone" + }, + { + "code": "HUF", + "local": "Hungary", + "symbol": "Ft", + "name": "Hungarian forint" + }, + { + "code": "TWD", + "local": "Taiwan", + "symbol": "$", + "name": "New Taiwan dollar" + }, { "code": "XPF", "local": "Wallis and Futuna", @@ -6,65 +42,23 @@ "name": "CFP franc" }, { - "code": "ISK", - "local": "Iceland", - "symbol": "kr", - "name": "Icelandic króna" + "code": "BBD", + "local": "Barbados", + "symbol": "$", + "name": "Barbadian dollar" }, { - "code": "EUR", - "local": "Luxembourg", - "symbol": "€", - "name": "Euro" + "code": "NZD", + "local": "Pitcairn Islands", + "symbol": "$", + "name": "New Zealand dollar" }, { "code": "XOF", - "local": "Mali", + "local": "Ivory Coast", "symbol": "Fr", "name": "West African CFA franc" }, - { - "code": "KMF", - "local": "Comoros", - "symbol": "Fr", - "name": "Comorian franc" - }, - { - "code": "AUD", - "local": "Australia", - "symbol": "$", - "name": "Australian dollar" - }, - { - "code": "EUR", - "local": "Estonia", - "symbol": "€", - "name": "Euro" - }, - { - "code": "CAD", - "local": "Canada", - "symbol": "$", - "name": "Canadian dollar" - }, - { - "code": "BYN", - "local": "Belarus", - "symbol": "Br", - "name": "Belarusian ruble" - }, - { - "code": "GYD", - "local": "Guyana", - "symbol": "$", - "name": "Guyanese dollar" - }, - { - "code": "GMD", - "local": "Gambia", - "symbol": "D", - "name": "dalasi" - }, { "code": "TND", "local": "Tunisia", @@ -72,28 +66,10 @@ "name": "Tunisian dinar" }, { - "code": "XAF", - "local": "Cameroon", - "symbol": "Fr", - "name": "Central African CFA franc" - }, - { - "code": "RWF", - "local": "Rwanda", - "symbol": "Fr", - "name": "Rwandan franc" - }, - { - "code": "KHR", - "local": "Cambodia", - "symbol": "៛", - "name": "Cambodian riel" - }, - { - "code": "USD", - "local": "Cambodia", - "symbol": "$", - "name": "United States dollar" + "code": "EUR", + "local": "Italy", + "symbol": "€", + "name": "Euro" }, { "code": "XOF", @@ -102,82 +78,10 @@ "name": "West African CFA franc" }, { - "code": "EUR", - "local": "Greece", - "symbol": "€", - "name": "Euro" - }, - { - "code": "KRW", - "local": "South Korea", - "symbol": "₩", - "name": "South Korean won" - }, - { - "code": "MUR", - "local": "Mauritius", - "symbol": "₨", - "name": "Mauritian rupee" - }, - { - "code": "USD", - "local": "United States Virgin Islands", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "EUR", - "local": "Åland Islands", - "symbol": "€", - "name": "Euro" - }, - { - "code": "EUR", - "local": "San Marino", - "symbol": "€", - "name": "Euro" - }, - { - "code": "MVR", - "local": "Maldives", - "symbol": ".ރ", - "name": "Maldivian rufiyaa" - }, - { - "code": "VUV", - "local": "Vanuatu", - "symbol": "Vt", - "name": "Vanuatu vatu" - }, - { - "code": "MWK", - "local": "Malawi", - "symbol": "MK", - "name": "Malawian kwacha" - }, - { - "code": "EGP", - "local": "Egypt", - "symbol": "£", - "name": "Egyptian pound" - }, - { - "code": "XOF", - "local": "Senegal", - "symbol": "Fr", - "name": "West African CFA franc" - }, - { - "code": "GEL", - "local": "Georgia", - "symbol": "₾", - "name": "lari" - }, - { - "code": "NZD", - "local": "New Zealand", - "symbol": "$", - "name": "New Zealand dollar" + "code": "IDR", + "local": "Indonesia", + "symbol": "Rp", + "name": "Indonesian rupiah" }, { "code": "CVE", @@ -186,28 +90,10 @@ "name": "Cape Verdean escudo" }, { - "code": "EUR", - "local": "Italy", - "symbol": "€", - "name": "Euro" - }, - { - "code": "EUR", - "local": "Monaco", - "symbol": "€", - "name": "Euro" - }, - { - "code": "EUR", - "local": "Slovakia", - "symbol": "€", - "name": "Euro" - }, - { - "code": "UYU", - "local": "Uruguay", + "code": "XCD", + "local": "Saint Kitts and Nevis", "symbol": "$", - "name": "Uruguayan peso" + "name": "Eastern Caribbean dollar" }, { "code": "LAK", @@ -215,6 +101,114 @@ "symbol": "₭", "name": "Lao kip" }, + { + "code": "USD", + "local": "Caribbean Netherlands", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "UGX", + "local": "Uganda", + "symbol": "Sh", + "name": "Ugandan shilling" + }, + { + "code": "EUR", + "local": "Andorra", + "symbol": "€", + "name": "Euro" + }, + { + "code": "BIF", + "local": "Burundi", + "symbol": "Fr", + "name": "Burundian franc" + }, + { + "code": "ZAR", + "local": "South Africa", + "symbol": "R", + "name": "South African rand" + }, + { + "code": "EUR", + "local": "France", + "symbol": "€", + "name": "Euro" + }, + { + "code": "LYD", + "local": "Libya", + "symbol": "ل.د", + "name": "Libyan dinar" + }, + { + "code": "MXN", + "local": "Mexico", + "symbol": "$", + "name": "Mexican peso" + }, + { + "code": "XAF", + "local": "Gabon", + "symbol": "Fr", + "name": "Central African CFA franc" + }, + { + "code": "USD", + "local": "Northern Mariana Islands", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "MKD", + "local": "North Macedonia", + "symbol": "den", + "name": "denar" + }, + { + "code": "CNY", + "local": "China", + "symbol": "¥", + "name": "Chinese yuan" + }, + { + "code": "YER", + "local": "Yemen", + "symbol": "﷼", + "name": "Yemeni rial" + }, + { + "code": "EUR", + "local": "Saint Barthélemy", + "symbol": "€", + "name": "Euro" + }, + { + "code": "GBP", + "local": "Guernsey", + "symbol": "£", + "name": "British pound" + }, + { + "code": "GGP", + "local": "Guernsey", + "symbol": "£", + "name": "Guernsey pound" + }, + { + "code": "SBD", + "local": "Solomon Islands", + "symbol": "$", + "name": "Solomon Islands dollar" + }, + { + "code": "NOK", + "local": "Svalbard and Jan Mayen", + "symbol": "kr", + "name": "krone" + }, { "code": "DKK", "local": "Faroe Islands", @@ -227,180 +221,6 @@ "symbol": "kr", "name": "Faroese króna" }, - { - "code": "NZD", - "local": "Niue", - "symbol": "$", - "name": "New Zealand dollar" - }, - { - "code": "MKD", - "local": "North Macedonia", - "symbol": "den", - "name": "denar" - }, - { - "code": "CLP", - "local": "Chile", - "symbol": "$", - "name": "Chilean peso" - }, - { - "code": "EUR", - "local": "Cyprus", - "symbol": "€", - "name": "Euro" - }, - { - "code": "MOP", - "local": "Macau", - "symbol": "P", - "name": "Macanese pataca" - }, - { - "code": "USD", - "local": "El Salvador", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "JOD", - "local": "Jordan", - "symbol": "د.ا", - "name": "Jordanian dinar" - }, - { - "code": "JMD", - "local": "Jamaica", - "symbol": "$", - "name": "Jamaican dollar" - }, - { - "code": "BBD", - "local": "Barbados", - "symbol": "$", - "name": "Barbadian dollar" - }, - { - "code": "DZD", - "local": "Western Sahara", - "symbol": "دج", - "name": "Algerian dinar" - }, - { - "code": "MAD", - "local": "Western Sahara", - "symbol": "DH", - "name": "Moroccan dirham" - }, - { - "code": "MRU", - "local": "Western Sahara", - "symbol": "UM", - "name": "Mauritanian ouguiya" - }, - { - "code": "QAR", - "local": "Qatar", - "symbol": "ر.ق", - "name": "Qatari riyal" - }, - { - "code": "GTQ", - "local": "Guatemala", - "symbol": "Q", - "name": "Guatemalan quetzal" - }, - { - "code": "USD", - "local": "Micronesia", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "XCD", - "local": "Montserrat", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "PGK", - "local": "Papua New Guinea", - "symbol": "K", - "name": "Papua New Guinean kina" - }, - { - "code": "BRL", - "local": "Brazil", - "symbol": "R$", - "name": "Brazilian real" - }, - { - "code": "EUR", - "local": "Lithuania", - "symbol": "€", - "name": "Euro" - }, - { - "code": "EUR", - "local": "French Guiana", - "symbol": "€", - "name": "Euro" - }, - { - "code": "MDL", - "local": "Moldova", - "symbol": "L", - "name": "Moldovan leu" - }, - { - "code": "KGS", - "local": "Kyrgyzstan", - "symbol": "с", - "name": "Kyrgyzstani som" - }, - { - "code": "ANG", - "local": "Curaçao", - "symbol": "ƒ", - "name": "Netherlands Antillean guilder" - }, - { - "code": "VND", - "local": "Vietnam", - "symbol": "₫", - "name": "Vietnamese đồng" - }, - { - "code": "AOA", - "local": "Angola", - "symbol": "Kz", - "name": "Angolan kwanza" - }, - { - "code": "MYR", - "local": "Malaysia", - "symbol": "RM", - "name": "Malaysian ringgit" - }, - { - "code": "CHF", - "local": "Switzerland", - "symbol": "Fr.", - "name": "Swiss franc" - }, - { - "code": "THB", - "local": "Thailand", - "symbol": "฿", - "name": "Thai baht" - }, - { - "code": "DOP", - "local": "Dominican Republic", - "symbol": "$", - "name": "Dominican peso" - }, { "code": "UZS", "local": "Uzbekistan", @@ -408,400 +228,16 @@ "name": "Uzbekistani soʻm" }, { - "code": "XAF", - "local": "Chad", + "code": "EGP", + "local": "Egypt", + "symbol": "£", + "name": "Egyptian pound" + }, + { + "code": "XOF", + "local": "Senegal", "symbol": "Fr", - "name": "Central African CFA franc" - }, - { - "code": "AUD", - "local": "Cocos (Keeling) Islands", - "symbol": "$", - "name": "Australian dollar" - }, - { - "code": "GNF", - "local": "Guinea", - "symbol": "Fr", - "name": "Guinean franc" - }, - { - "code": "USD", - "local": "Turks and Caicos Islands", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "USD", - "local": "Puerto Rico", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "BTN", - "local": "Bhutan", - "symbol": "Nu.", - "name": "Bhutanese ngultrum" - }, - { - "code": "INR", - "local": "Bhutan", - "symbol": "₹", - "name": "Indian rupee" - }, - { - "code": "KYD", - "local": "Cayman Islands", - "symbol": "$", - "name": "Cayman Islands dollar" - }, - { - "code": "USD", - "local": "Marshall Islands", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "XCD", - "local": "Anguilla", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "MRU", - "local": "Mauritania", - "symbol": "UM", - "name": "Mauritanian ouguiya" - }, - { - "code": "NOK", - "local": "Norway", - "symbol": "kr", - "name": "Norwegian krone" - }, - { - "code": "EUR", - "local": "Martinique", - "symbol": "€", - "name": "Euro" - }, - { - "code": "ILS", - "local": "Israel", - "symbol": "₪", - "name": "Israeli new shekel" - }, - { - "code": "EUR", - "local": "Saint Barthélemy", - "symbol": "€", - "name": "Euro" - }, - { - "code": "USD", - "local": "Ecuador", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "XCD", - "local": "Grenada", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "EUR", - "local": "Croatia", - "symbol": "€", - "name": "Euro" - }, - { - "code": "BND", - "local": "Brunei", - "symbol": "$", - "name": "Brunei dollar" - }, - { - "code": "SGD", - "local": "Brunei", - "symbol": "$", - "name": "Singapore dollar" - }, - { - "code": "IQD", - "local": "Iraq", - "symbol": "ع.د", - "name": "Iraqi dinar" - }, - { - "code": "JPY", - "local": "Japan", - "symbol": "¥", - "name": "Japanese yen" - }, - { - "code": "LSL", - "local": "Lesotho", - "symbol": "L", - "name": "Lesotho loti" - }, - { - "code": "ZAR", - "local": "Lesotho", - "symbol": "R", - "name": "South African rand" - }, - { - "code": "AUD", - "local": "Tuvalu", - "symbol": "$", - "name": "Australian dollar" - }, - { - "code": "TVD", - "local": "Tuvalu", - "symbol": "$", - "name": "Tuvaluan dollar" - }, - { - "code": "EUR", - "local": "Finland", - "symbol": "€", - "name": "Euro" - }, - { - "code": "SSP", - "local": "South Sudan", - "symbol": "£", - "name": "South Sudanese pound" - }, - { - "code": "USD", - "local": "United States Minor Outlying Islands", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "GBP", - "local": "Saint Helena, Ascension and Tristan da Cunha", - "symbol": "£", - "name": "Pound sterling" - }, - { - "code": "SHP", - "local": "Saint Helena, Ascension and Tristan da Cunha", - "symbol": "£", - "name": "Saint Helena pound" - }, - { - "code": "AFN", - "local": "Afghanistan", - "symbol": "؋", - "name": "Afghan afghani" - }, - { - "code": "SBD", - "local": "Solomon Islands", - "symbol": "$", - "name": "Solomon Islands dollar" - }, - { - "code": "CNY", - "local": "China", - "symbol": "¥", - "name": "Chinese yuan" - }, - { - "code": "ERN", - "local": "Eritrea", - "symbol": "Nfk", - "name": "Eritrean nakfa" - }, - { - "code": "RUB", - "local": "Russia", - "symbol": "₽", - "name": "Russian ruble" - }, - { - "code": "EUR", - "local": "Andorra", - "symbol": "€", - "name": "Euro" - }, - { - "code": "AMD", - "local": "Armenia", - "symbol": "֏", - "name": "Armenian dram" - }, - { - "code": "EUR", - "local": "Austria", - "symbol": "€", - "name": "Euro" - }, - { - "code": "SRD", - "local": "Suriname", - "symbol": "$", - "name": "Surinamese dollar" - }, - { - "code": "EUR", - "local": "Spain", - "symbol": "€", - "name": "Euro" - }, - { - "code": "NZD", - "local": "Tokelau", - "symbol": "$", - "name": "New Zealand dollar" - }, - { - "code": "BSD", - "local": "Bahamas", - "symbol": "$", - "name": "Bahamian dollar" - }, - { - "code": "USD", - "local": "Bahamas", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "ANG", - "local": "Sint Maarten", - "symbol": "ƒ", - "name": "Netherlands Antillean guilder" - }, - { - "code": "BZD", - "local": "Belize", - "symbol": "$", - "name": "Belize dollar" - }, - { - "code": "GBP", - "local": "Jersey", - "symbol": "£", - "name": "British pound" - }, - { - "code": "JEP", - "local": "Jersey", - "symbol": "£", - "name": "Jersey pound" - }, - { - "code": "SEK", - "local": "Sweden", - "symbol": "kr", - "name": "Swedish krona" - }, - { - "code": "BWP", - "local": "Botswana", - "symbol": "P", - "name": "Botswana pula" - }, - { - "code": "GBP", - "local": "Isle of Man", - "symbol": "£", - "name": "British pound" - }, - { - "code": "IMP", - "local": "Isle of Man", - "symbol": "£", - "name": "Manx pound" - }, - { - "code": "AED", - "local": "United Arab Emirates", - "symbol": "د.إ", - "name": "United Arab Emirates dirham" - }, - { - "code": "IRR", - "local": "Iran", - "symbol": "﷼", - "name": "Iranian rial" - }, - { - "code": "XAF", - "local": "Gabon", - "symbol": "Fr", - "name": "Central African CFA franc" - }, - { - "code": "XCD", - "local": "Saint Kitts and Nevis", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "XAF", - "local": "Equatorial Guinea", - "symbol": "Fr", - "name": "Central African CFA franc" - }, - { - "code": "STN", - "local": "São Tomé and Príncipe", - "symbol": "Db", - "name": "São Tomé and Príncipe dobra" - }, - { - "code": "DKK", - "local": "Greenland", - "symbol": "kr.", - "name": "krone" - }, - { - "code": "BDT", - "local": "Bangladesh", - "symbol": "৳", - "name": "Bangladeshi taka" - }, - { - "code": "RON", - "local": "Romania", - "symbol": "lei", - "name": "Romanian leu" - }, - { - "code": "USD", - "local": "British Indian Ocean Territory", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "SDG", - "local": "Sudan", - "symbol": "", - "name": "Sudanese pound" - }, - { - "code": "BAM", - "local": "Bosnia and Herzegovina", - "symbol": "", - "name": "Bosnia and Herzegovina convertible mark" - }, - { - "code": "EUR", - "local": "Malta", - "symbol": "€", - "name": "Euro" - }, - { - "code": "SCR", - "local": "Seychelles", - "symbol": "₨", - "name": "Seychellois rupee" + "name": "West African CFA franc" }, { "code": "LKR", @@ -809,96 +245,6 @@ "symbol": "Rs රු", "name": "Sri Lankan rupee" }, - { - "code": "MXN", - "local": "Mexico", - "symbol": "$", - "name": "Mexican peso" - }, - { - "code": "YER", - "local": "Yemen", - "symbol": "﷼", - "name": "Yemeni rial" - }, - { - "code": "USD", - "local": "British Virgin Islands", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "EUR", - "local": "Netherlands", - "symbol": "€", - "name": "Euro" - }, - { - "code": "PYG", - "local": "Paraguay", - "symbol": "₲", - "name": "Paraguayan guaraní" - }, - { - "code": "GBP", - "local": "United Kingdom", - "symbol": "£", - "name": "British pound" - }, - { - "code": "VES", - "local": "Venezuela", - "symbol": "Bs.S.", - "name": "Venezuelan bolívar soberano" - }, - { - "code": "UAH", - "local": "Ukraine", - "symbol": "₴", - "name": "Ukrainian hryvnia" - }, - { - "code": "MAD", - "local": "Morocco", - "symbol": "د.م.", - "name": "Moroccan dirham" - }, - { - "code": "EUR", - "local": "Portugal", - "symbol": "€", - "name": "Euro" - }, - { - "code": "PKR", - "local": "Pakistan", - "symbol": "₨", - "name": "Pakistani rupee" - }, - { - "code": "XCD", - "local": "Saint Vincent and the Grenadines", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "KPW", - "local": "North Korea", - "symbol": "₩", - "name": "North Korean won" - }, - { - "code": "EUR", - "local": "Slovenia", - "symbol": "€", - "name": "Euro" - }, - { - "code": "XOF", - "local": "Ivory Coast", - "symbol": "Fr", - "name": "West African CFA franc" - }, { "code": "EGP", "local": "Palestine", @@ -918,34 +264,40 @@ "name": "Jordanian dinar" }, { - "code": "USD", - "local": "Caribbean Netherlands", + "code": "BDT", + "local": "Bangladesh", + "symbol": "৳", + "name": "Bangladeshi taka" + }, + { + "code": "PEN", + "local": "Peru", + "symbol": "S/ ", + "name": "Peruvian sol" + }, + { + "code": "SGD", + "local": "Singapore", "symbol": "$", - "name": "United States dollar" + "name": "Singapore dollar" }, { - "code": "EUR", - "local": "Belgium", - "symbol": "€", - "name": "Euro" + "code": "TRY", + "local": "Turkey", + "symbol": "₺", + "name": "Turkish lira" }, { - "code": "ZWL", - "local": "Zimbabwe", - "symbol": "$", - "name": "Zimbabwean dollar" + "code": "AFN", + "local": "Afghanistan", + "symbol": "؋", + "name": "Afghan afghani" }, { - "code": "TZS", - "local": "Tanzania", - "symbol": "Sh", - "name": "Tanzanian shilling" - }, - { - "code": "XOF", - "local": "Togo", - "symbol": "Fr", - "name": "West African CFA franc" + "code": "AWG", + "local": "Aruba", + "symbol": "ƒ", + "name": "Aruban florin" }, { "code": "CKD", @@ -959,89 +311,41 @@ "symbol": "$", "name": "New Zealand dollar" }, + { + "code": "GBP", + "local": "United Kingdom", + "symbol": "£", + "name": "British pound" + }, + { + "code": "ZMW", + "local": "Zambia", + "symbol": "ZK", + "name": "Zambian kwacha" + }, { "code": "EUR", - "local": "Guadeloupe", + "local": "Finland", "symbol": "€", "name": "Euro" }, { - "code": "XPF", - "local": "New Caledonia", - "symbol": "₣", - "name": "CFP franc" - }, - { - "code": "XCD", - "local": "Saint Lucia", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "SHP", - "local": "South Georgia", - "symbol": "£", - "name": "Saint Helena pound" - }, - { - "code": "PLN", - "local": "Poland", - "symbol": "zł", - "name": "Polish złoty" - }, - { - "code": "WST", - "local": "Samoa", - "symbol": "T", - "name": "Samoan tālā" - }, - { - "code": "CZK", - "local": "Czechia", - "symbol": "Kč", - "name": "Czech koruna" - }, - { - "code": "IDR", - "local": "Indonesia", - "symbol": "Rp", - "name": "Indonesian rupiah" - }, - { - "code": "BOB", - "local": "Bolivia", - "symbol": "Bs.", - "name": "Bolivian boliviano" - }, - { - "code": "COP", - "local": "Colombia", - "symbol": "$", - "name": "Colombian peso" - }, - { - "code": "HNL", - "local": "Honduras", - "symbol": "L", - "name": "Honduran lempira" - }, - { - "code": "DKK", - "local": "Denmark", - "symbol": "kr", - "name": "Danish krone" - }, - { - "code": "XAF", - "local": "Central African Republic", + "code": "XOF", + "local": "Niger", "symbol": "Fr", - "name": "Central African CFA franc" + "name": "West African CFA franc" }, { - "code": "LYD", - "local": "Libya", - "symbol": "ل.د", - "name": "Libyan dinar" + "code": "AUD", + "local": "Christmas Island", + "symbol": "$", + "name": "Australian dollar" + }, + { + "code": "NZD", + "local": "Tokelau", + "symbol": "$", + "name": "New Zealand dollar" }, { "code": "XOF", @@ -1050,29 +354,185 @@ "name": "West African CFA franc" }, { - "code": "MNT", - "local": "Mongolia", - "symbol": "₮", - "name": "Mongolian tögrög" + "code": "AZN", + "local": "Azerbaijan", + "symbol": "₼", + "name": "Azerbaijani manat" }, { - "code": "CDF", - "local": "DR Congo", - "symbol": "FC", - "name": "Congolese franc" + "code": "EUR", + "local": "Réunion", + "symbol": "€", + "name": "Euro" }, { - "code": "FKP", - "local": "Falkland Islands", - "symbol": "£", - "name": "Falkland Islands pound" + "code": "DJF", + "local": "Djibouti", + "symbol": "Fr", + "name": "Djiboutian franc" + }, + { + "code": "KPW", + "local": "North Korea", + "symbol": "₩", + "name": "North Korean won" + }, + { + "code": "MUR", + "local": "Mauritius", + "symbol": "₨", + "name": "Mauritian rupee" + }, + { + "code": "XCD", + "local": "Montserrat", + "symbol": "$", + "name": "Eastern Caribbean dollar" + }, + { + "code": "USD", + "local": "United States Virgin Islands", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "COP", + "local": "Colombia", + "symbol": "$", + "name": "Colombian peso" + }, + { + "code": "EUR", + "local": "Greece", + "symbol": "€", + "name": "Euro" + }, + { + "code": "EUR", + "local": "Croatia", + "symbol": "€", + "name": "Euro" + }, + { + "code": "MAD", + "local": "Morocco", + "symbol": "د.م.", + "name": "Moroccan dirham" + }, + { + "code": "DZD", + "local": "Algeria", + "symbol": "د.ج", + "name": "Algerian dinar" + }, + { + "code": "EUR", + "local": "Netherlands", + "symbol": "€", + "name": "Euro" + }, + { + "code": "SDG", + "local": "Sudan", + "symbol": "ج.س", + "name": "Sudanese pound" + }, + { + "code": "FJD", + "local": "Fiji", + "symbol": "$", + "name": "Fijian dollar" + }, + { + "code": "CHF", + "local": "Liechtenstein", + "symbol": "Fr", + "name": "Swiss franc" + }, + { + "code": "NPR", + "local": "Nepal", + "symbol": "₨", + "name": "Nepalese rupee" + }, + { + "code": "USD", + "local": "Puerto Rico", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "GEL", + "local": "Georgia", + "symbol": "₾", + "name": "lari" + }, + { + "code": "PKR", + "local": "Pakistan", + "symbol": "₨", + "name": "Pakistani rupee" + }, + { + "code": "EUR", + "local": "Monaco", + "symbol": "€", + "name": "Euro" + }, + { + "code": "BWP", + "local": "Botswana", + "symbol": "P", + "name": "Botswana pula" + }, + { + "code": "LBP", + "local": "Lebanon", + "symbol": "ل.ل", + "name": "Lebanese pound" + }, + { + "code": "PGK", + "local": "Papua New Guinea", + "symbol": "K", + "name": "Papua New Guinean kina" + }, + { + "code": "EUR", + "local": "Mayotte", + "symbol": "€", + "name": "Euro" + }, + { + "code": "DOP", + "local": "Dominican Republic", + "symbol": "$", + "name": "Dominican peso" }, { "code": "AUD", - "local": "Nauru", + "local": "Norfolk Island", "symbol": "$", "name": "Australian dollar" }, + { + "code": "QAR", + "local": "Qatar", + "symbol": "ر.ق", + "name": "Qatari riyal" + }, + { + "code": "MGA", + "local": "Madagascar", + "symbol": "Ar", + "name": "Malagasy ariary" + }, + { + "code": "INR", + "local": "India", + "symbol": "₹", + "name": "Indian rupee" + }, { "code": "SYP", "local": "Syria", @@ -1086,130 +546,46 @@ "name": "Euro" }, { - "code": "EUR", - "local": "France", - "symbol": "€", - "name": "Euro" + "code": "SZL", + "local": "Eswatini", + "symbol": "L", + "name": "Swazi lilangeni" }, { - "code": "ZMW", - "local": "Zambia", - "symbol": "ZK", - "name": "Zambian kwacha" + "code": "ZAR", + "local": "Eswatini", + "symbol": "R", + "name": "South African rand" }, { - "code": "MMK", - "local": "Myanmar", - "symbol": "Ks", - "name": "Burmese kyat" - }, - { - "code": "EUR", - "local": "Saint Pierre and Miquelon", - "symbol": "€", - "name": "Euro" - }, - { - "code": "CRC", - "local": "Costa Rica", - "symbol": "₡", - "name": "Costa Rican colón" - }, - { - "code": "SOS", - "local": "Somalia", - "symbol": "Sh", - "name": "Somali shilling" - }, - { - "code": "EUR", - "local": "Ireland", - "symbol": "€", - "name": "Euro" - }, - { - "code": "XPF", - "local": "French Polynesia", - "symbol": "₣", - "name": "CFP franc" - }, - { - "code": "NZD", - "local": "Pitcairn Islands", - "symbol": "$", - "name": "New Zealand dollar" - }, - { - "code": "HUF", - "local": "Hungary", - "symbol": "Ft", - "name": "Hungarian forint" - }, - { - "code": "TRY", - "local": "Turkey", - "symbol": "₺", - "name": "Turkish lira" - }, - { - "code": "OMR", - "local": "Oman", - "symbol": "ر.ع.", - "name": "Omani rial" + "code": "PYG", + "local": "Paraguay", + "symbol": "₲", + "name": "Paraguayan guaraní" }, { "code": "USD", - "local": "Guam", + "local": "El Salvador", "symbol": "$", "name": "United States dollar" }, { - "code": "NPR", - "local": "Nepal", - "symbol": "₨", - "name": "Nepalese rupee" - }, - { - "code": "CHF", - "local": "Liechtenstein", - "symbol": "Fr", - "name": "Swiss franc" - }, - { - "code": "MGA", - "local": "Madagascar", - "symbol": "Ar", - "name": "Malagasy ariary" - }, - { - "code": "KZT", - "local": "Kazakhstan", - "symbol": "₸", - "name": "Kazakhstani tenge" - }, - { - "code": "DJF", - "local": "Djibouti", - "symbol": "Fr", - "name": "Djiboutian franc" - }, - { - "code": "GIP", - "local": "Gibraltar", - "symbol": "£", - "name": "Gibraltar pound" + "code": "UAH", + "local": "Ukraine", + "symbol": "₴", + "name": "Ukrainian hryvnia" }, { "code": "GBP", - "local": "Guernsey", + "local": "Isle of Man", "symbol": "£", "name": "British pound" }, { - "code": "GGP", - "local": "Guernsey", + "code": "IMP", + "local": "Isle of Man", "symbol": "£", - "name": "Guernsey pound" + "name": "Manx pound" }, { "code": "NAD", @@ -1224,10 +600,22 @@ "name": "South African rand" }, { - "code": "XAF", - "local": "Republic of the Congo", - "symbol": "Fr", - "name": "Central African CFA franc" + "code": "AED", + "local": "United Arab Emirates", + "symbol": "د.إ", + "name": "United Arab Emirates dirham" + }, + { + "code": "BGN", + "local": "Bulgaria", + "symbol": "лв", + "name": "Bulgarian lev" + }, + { + "code": "DKK", + "local": "Greenland", + "symbol": "kr.", + "name": "krone" }, { "code": "EUR", @@ -1236,10 +624,22 @@ "name": "Euro" }, { - "code": "EUR", - "local": "Vatican City", - "symbol": "€", - "name": "Euro" + "code": "KHR", + "local": "Cambodia", + "symbol": "៛", + "name": "Cambodian riel" + }, + { + "code": "USD", + "local": "Cambodia", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "IQD", + "local": "Iraq", + "symbol": "ع.د", + "name": "Iraqi dinar" }, { "code": "EUR", @@ -1248,64 +648,10 @@ "name": "Euro" }, { - "code": "ALL", - "local": "Albania", - "symbol": "L", - "name": "Albanian lek" - }, - { - "code": "DZD", - "local": "Algeria", - "symbol": "د.ج", - "name": "Algerian dinar" - }, - { - "code": "EUR", - "local": "Mayotte", - "symbol": "€", - "name": "Euro" - }, - { - "code": "HTG", - "local": "Haiti", - "symbol": "G", - "name": "Haitian gourde" - }, - { - "code": "NOK", - "local": "Svalbard and Jan Mayen", + "code": "SEK", + "local": "Sweden", "symbol": "kr", - "name": "krone" - }, - { - "code": "TOP", - "local": "Tonga", - "symbol": "T$", - "name": "Tongan paʻanga" - }, - { - "code": "HKD", - "local": "Hong Kong", - "symbol": "$", - "name": "Hong Kong dollar" - }, - { - "code": "SGD", - "local": "Singapore", - "symbol": "$", - "name": "Singapore dollar" - }, - { - "code": "XCD", - "local": "Antigua and Barbuda", - "symbol": "$", - "name": "Eastern Caribbean dollar" - }, - { - "code": "SAR", - "local": "Saudi Arabia", - "symbol": "ر.س", - "name": "Saudi riyal" + "name": "Swedish krona" }, { "code": "CUC", @@ -1319,6 +665,462 @@ "symbol": "$", "name": "Cuban peso" }, + { + "code": "KGS", + "local": "Kyrgyzstan", + "symbol": "с", + "name": "Kyrgyzstani som" + }, + { + "code": "RUB", + "local": "Russia", + "symbol": "₽", + "name": "Russian ruble" + }, + { + "code": "MYR", + "local": "Malaysia", + "symbol": "RM", + "name": "Malaysian ringgit" + }, + { + "code": "STN", + "local": "São Tomé and Príncipe", + "symbol": "Db", + "name": "São Tomé and Príncipe dobra" + }, + { + "code": "EUR", + "local": "Cyprus", + "symbol": "€", + "name": "Euro" + }, + { + "code": "CAD", + "local": "Canada", + "symbol": "$", + "name": "Canadian dollar" + }, + { + "code": "MWK", + "local": "Malawi", + "symbol": "MK", + "name": "Malawian kwacha" + }, + { + "code": "SAR", + "local": "Saudi Arabia", + "symbol": "ر.س", + "name": "Saudi riyal" + }, + { + "code": "BAM", + "local": "Bosnia and Herzegovina", + "symbol": "KM", + "name": "Bosnia and Herzegovina convertible mark" + }, + { + "code": "ETB", + "local": "Ethiopia", + "symbol": "Br", + "name": "Ethiopian birr" + }, + { + "code": "EUR", + "local": "Spain", + "symbol": "€", + "name": "Euro" + }, + { + "code": "EUR", + "local": "Slovenia", + "symbol": "€", + "name": "Euro" + }, + { + "code": "OMR", + "local": "Oman", + "symbol": "ر.ع.", + "name": "Omani rial" + }, + { + "code": "EUR", + "local": "Saint Pierre and Miquelon", + "symbol": "€", + "name": "Euro" + }, + { + "code": "MOP", + "local": "Macau", + "symbol": "P", + "name": "Macanese pataca" + }, + { + "code": "EUR", + "local": "San Marino", + "symbol": "€", + "name": "Euro" + }, + { + "code": "LSL", + "local": "Lesotho", + "symbol": "L", + "name": "Lesotho loti" + }, + { + "code": "ZAR", + "local": "Lesotho", + "symbol": "R", + "name": "South African rand" + }, + { + "code": "USD", + "local": "Marshall Islands", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "ANG", + "local": "Sint Maarten", + "symbol": "ƒ", + "name": "Netherlands Antillean guilder" + }, + { + "code": "ISK", + "local": "Iceland", + "symbol": "kr", + "name": "Icelandic króna" + }, + { + "code": "EUR", + "local": "Luxembourg", + "symbol": "€", + "name": "Euro" + }, + { + "code": "ARS", + "local": "Argentina", + "symbol": "$", + "name": "Argentine peso" + }, + { + "code": "USD", + "local": "Turks and Caicos Islands", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "AUD", + "local": "Nauru", + "symbol": "$", + "name": "Australian dollar" + }, + { + "code": "AUD", + "local": "Cocos (Keeling) Islands", + "symbol": "$", + "name": "Australian dollar" + }, + { + "code": "DZD", + "local": "Western Sahara", + "symbol": "دج", + "name": "Algerian dinar" + }, + { + "code": "MAD", + "local": "Western Sahara", + "symbol": "DH", + "name": "Moroccan dirham" + }, + { + "code": "MRU", + "local": "Western Sahara", + "symbol": "UM", + "name": "Mauritanian ouguiya" + }, + { + "code": "XCD", + "local": "Dominica", + "symbol": "$", + "name": "Eastern Caribbean dollar" + }, + { + "code": "CRC", + "local": "Costa Rica", + "symbol": "₡", + "name": "Costa Rican colón" + }, + { + "code": "AUD", + "local": "Australia", + "symbol": "$", + "name": "Australian dollar" + }, + { + "code": "THB", + "local": "Thailand", + "symbol": "฿", + "name": "Thai baht" + }, + { + "code": "HTG", + "local": "Haiti", + "symbol": "G", + "name": "Haitian gourde" + }, + { + "code": "AUD", + "local": "Tuvalu", + "symbol": "$", + "name": "Australian dollar" + }, + { + "code": "TVD", + "local": "Tuvalu", + "symbol": "$", + "name": "Tuvaluan dollar" + }, + { + "code": "HNL", + "local": "Honduras", + "symbol": "L", + "name": "Honduran lempira" + }, + { + "code": "XAF", + "local": "Equatorial Guinea", + "symbol": "Fr", + "name": "Central African CFA franc" + }, + { + "code": "XCD", + "local": "Saint Lucia", + "symbol": "$", + "name": "Eastern Caribbean dollar" + }, + { + "code": "XPF", + "local": "French Polynesia", + "symbol": "₣", + "name": "CFP franc" + }, + { + "code": "BYN", + "local": "Belarus", + "symbol": "Br", + "name": "Belarusian ruble" + }, + { + "code": "EUR", + "local": "Latvia", + "symbol": "€", + "name": "Euro" + }, + { + "code": "USD", + "local": "Palau", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "EUR", + "local": "Guadeloupe", + "symbol": "€", + "name": "Euro" + }, + { + "code": "PHP", + "local": "Philippines", + "symbol": "₱", + "name": "Philippine peso" + }, + { + "code": "GIP", + "local": "Gibraltar", + "symbol": "£", + "name": "Gibraltar pound" + }, + { + "code": "DKK", + "local": "Denmark", + "symbol": "kr", + "name": "Danish krone" + }, + { + "code": "XAF", + "local": "Cameroon", + "symbol": "Fr", + "name": "Central African CFA franc" + }, + { + "code": "GNF", + "local": "Guinea", + "symbol": "Fr", + "name": "Guinean franc" + }, + { + "code": "BHD", + "local": "Bahrain", + "symbol": ".د.ب", + "name": "Bahraini dinar" + }, + { + "code": "SRD", + "local": "Suriname", + "symbol": "$", + "name": "Surinamese dollar" + }, + { + "code": "CDF", + "local": "DR Congo", + "symbol": "FC", + "name": "Congolese franc" + }, + { + "code": "SOS", + "local": "Somalia", + "symbol": "Sh", + "name": "Somali shilling" + }, + { + "code": "CZK", + "local": "Czechia", + "symbol": "Kč", + "name": "Czech koruna" + }, + { + "code": "XPF", + "local": "New Caledonia", + "symbol": "₣", + "name": "CFP franc" + }, + { + "code": "VUV", + "local": "Vanuatu", + "symbol": "Vt", + "name": "Vanuatu vatu" + }, + { + "code": "GBP", + "local": "Saint Helena, Ascension and Tristan da Cunha", + "symbol": "£", + "name": "Pound sterling" + }, + { + "code": "SHP", + "local": "Saint Helena, Ascension and Tristan da Cunha", + "symbol": "£", + "name": "Saint Helena pound" + }, + { + "code": "XOF", + "local": "Togo", + "symbol": "Fr", + "name": "West African CFA franc" + }, + { + "code": "USD", + "local": "British Virgin Islands", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "KES", + "local": "Kenya", + "symbol": "Sh", + "name": "Kenyan shilling" + }, + { + "code": "NZD", + "local": "Niue", + "symbol": "$", + "name": "New Zealand dollar" + }, + { + "code": "RWF", + "local": "Rwanda", + "symbol": "Fr", + "name": "Rwandan franc" + }, + { + "code": "EUR", + "local": "Estonia", + "symbol": "€", + "name": "Euro" + }, + { + "code": "RON", + "local": "Romania", + "symbol": "lei", + "name": "Romanian leu" + }, + { + "code": "TTD", + "local": "Trinidad and Tobago", + "symbol": "$", + "name": "Trinidad and Tobago dollar" + }, + { + "code": "GYD", + "local": "Guyana", + "symbol": "$", + "name": "Guyanese dollar" + }, + { + "code": "USD", + "local": "Timor-Leste", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "VND", + "local": "Vietnam", + "symbol": "₫", + "name": "Vietnamese đồng" + }, + { + "code": "UYU", + "local": "Uruguay", + "symbol": "$", + "name": "Uruguayan peso" + }, + { + "code": "EUR", + "local": "Vatican City", + "symbol": "€", + "name": "Euro" + }, + { + "code": "HKD", + "local": "Hong Kong", + "symbol": "$", + "name": "Hong Kong dollar" + }, + { + "code": "EUR", + "local": "Austria", + "symbol": "€", + "name": "Euro" + }, + { + "code": "XCD", + "local": "Antigua and Barbuda", + "symbol": "$", + "name": "Eastern Caribbean dollar" + }, + { + "code": "TMT", + "local": "Turkmenistan", + "symbol": "m", + "name": "Turkmenistan manat" + }, + { + "code": "MZN", + "local": "Mozambique", + "symbol": "MT", + "name": "Mozambican metical" + }, { "code": "PAB", "local": "Panama", @@ -1332,124 +1134,46 @@ "name": "United States dollar" }, { - "code": "LRD", - "local": "Liberia", + "code": "USD", + "local": "Micronesia", "symbol": "$", - "name": "Liberian dollar" - }, - { - "code": "AZN", - "local": "Azerbaijan", - "symbol": "₼", - "name": "Azerbaijani manat" + "name": "United States dollar" }, { "code": "EUR", - "local": "Latvia", + "local": "Ireland", "symbol": "€", "name": "Euro" }, { - "code": "AUD", - "local": "Kiribati", - "symbol": "$", - "name": "Australian dollar" + "code": "ANG", + "local": "Curaçao", + "symbol": "ƒ", + "name": "Netherlands Antillean guilder" }, { - "code": "KID", - "local": "Kiribati", - "symbol": "$", - "name": "Kiribati dollar" + "code": "EUR", + "local": "French Guiana", + "symbol": "€", + "name": "Euro" }, { - "code": "ETB", - "local": "Ethiopia", - "symbol": "Br", - "name": "Ethiopian birr" + "code": "NOK", + "local": "Norway", + "symbol": "kr", + "name": "Norwegian krone" }, { - "code": "XOF", - "local": "Niger", + "code": "EUR", + "local": "Åland Islands", + "symbol": "€", + "name": "Euro" + }, + { + "code": "XAF", + "local": "Central African Republic", "symbol": "Fr", - "name": "West African CFA franc" - }, - { - "code": "TTD", - "local": "Trinidad and Tobago", - "symbol": "$", - "name": "Trinidad and Tobago dollar" - }, - { - "code": "SLL", - "local": "Sierra Leone", - "symbol": "Le", - "name": "Sierra Leonean leone" - }, - { - "code": "MZN", - "local": "Mozambique", - "symbol": "MT", - "name": "Mozambican metical" - }, - { - "code": "USD", - "local": "Palau", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "FJD", - "local": "Fiji", - "symbol": "$", - "name": "Fijian dollar" - }, - { - "code": "EUR", - "local": "Réunion", - "symbol": "€", - "name": "Euro" - }, - { - "code": "AUD", - "local": "Norfolk Island", - "symbol": "$", - "name": "Australian dollar" - }, - { - "code": "TMT", - "local": "Turkmenistan", - "symbol": "m", - "name": "Turkmenistan manat" - }, - { - "code": "TJS", - "local": "Tajikistan", - "symbol": "ЅМ", - "name": "Tajikistani somoni" - }, - { - "code": "LBP", - "local": "Lebanon", - "symbol": "ل.ل", - "name": "Lebanese pound" - }, - { - "code": "NGN", - "local": "Nigeria", - "symbol": "₦", - "name": "Nigerian naira" - }, - { - "code": "USD", - "local": "United States", - "symbol": "$", - "name": "United States dollar" - }, - { - "code": "ARS", - "local": "Argentina", - "symbol": "$", - "name": "Argentine peso" + "name": "Central African CFA franc" }, { "code": "XOF", @@ -1458,10 +1182,136 @@ "name": "West African CFA franc" }, { - "code": "AUD", - "local": "Christmas Island", + "code": "ERN", + "local": "Eritrea", + "symbol": "Nfk", + "name": "Eritrean nakfa" + }, + { + "code": "TZS", + "local": "Tanzania", + "symbol": "Sh", + "name": "Tanzanian shilling" + }, + { + "code": "KRW", + "local": "South Korea", + "symbol": "₩", + "name": "South Korean won" + }, + { + "code": "JOD", + "local": "Jordan", + "symbol": "د.ا", + "name": "Jordanian dinar" + }, + { + "code": "MRU", + "local": "Mauritania", + "symbol": "UM", + "name": "Mauritanian ouguiya" + }, + { + "code": "EUR", + "local": "Lithuania", + "symbol": "€", + "name": "Euro" + }, + { + "code": "USD", + "local": "United States Minor Outlying Islands", "symbol": "$", - "name": "Australian dollar" + "name": "United States dollar" + }, + { + "code": "EUR", + "local": "Slovakia", + "symbol": "€", + "name": "Euro" + }, + { + "code": "AOA", + "local": "Angola", + "symbol": "Kz", + "name": "Angolan kwanza" + }, + { + "code": "KZT", + "local": "Kazakhstan", + "symbol": "₸", + "name": "Kazakhstani tenge" + }, + { + "code": "MDL", + "local": "Moldova", + "symbol": "L", + "name": "Moldovan leu" + }, + { + "code": "XOF", + "local": "Mali", + "symbol": "Fr", + "name": "West African CFA franc" + }, + { + "code": "FKP", + "local": "Falkland Islands", + "symbol": "£", + "name": "Falkland Islands pound" + }, + { + "code": "AMD", + "local": "Armenia", + "symbol": "֏", + "name": "Armenian dram" + }, + { + "code": "WST", + "local": "Samoa", + "symbol": "T", + "name": "Samoan tālā" + }, + { + "code": "GBP", + "local": "Jersey", + "symbol": "£", + "name": "British pound" + }, + { + "code": "JEP", + "local": "Jersey", + "symbol": "£", + "name": "Jersey pound" + }, + { + "code": "JPY", + "local": "Japan", + "symbol": "¥", + "name": "Japanese yen" + }, + { + "code": "BOB", + "local": "Bolivia", + "symbol": "Bs.", + "name": "Bolivian boliviano" + }, + { + "code": "CLP", + "local": "Chile", + "symbol": "$", + "name": "Chilean peso" + }, + { + "code": "USD", + "local": "United States", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "XCD", + "local": "Saint Vincent and the Grenadines", + "symbol": "$", + "name": "Eastern Caribbean dollar" }, { "code": "BMD", @@ -1470,64 +1320,70 @@ "name": "Bermudian dollar" }, { - "code": "NIO", - "local": "Nicaragua", - "symbol": "C$", - "name": "Nicaraguan córdoba" - }, - { - "code": "SZL", - "local": "Eswatini", - "symbol": "L", - "name": "Swazi lilangeni" - }, - { - "code": "ZAR", - "local": "Eswatini", - "symbol": "R", - "name": "South African rand" - }, - { - "code": "BHD", - "local": "Bahrain", - "symbol": ".د.ب", - "name": "Bahraini dinar" - }, - { - "code": "KES", - "local": "Kenya", - "symbol": "Sh", - "name": "Kenyan shilling" - }, - { - "code": "RSD", - "local": "Serbia", - "symbol": "дин.", - "name": "Serbian dinar" + "code": "SCR", + "local": "Seychelles", + "symbol": "₨", + "name": "Seychellois rupee" }, { "code": "USD", - "local": "Timor-Leste", + "local": "British Indian Ocean Territory", "symbol": "$", "name": "United States dollar" }, { - "code": "XCD", - "local": "Dominica", - "symbol": "$", - "name": "Eastern Caribbean dollar" + "code": "GTQ", + "local": "Guatemala", + "symbol": "Q", + "name": "Guatemalan quetzal" }, { "code": "USD", - "local": "Northern Mariana Islands", + "local": "Ecuador", "symbol": "$", "name": "United States dollar" }, { - "code": "PHP", - "local": "Philippines", - "symbol": "₱", - "name": "Philippine peso" + "code": "EUR", + "local": "Martinique", + "symbol": "€", + "name": "Euro" + }, + { + "code": "TJS", + "local": "Tajikistan", + "symbol": "ЅМ", + "name": "Tajikistani somoni" + }, + { + "code": "EUR", + "local": "Malta", + "symbol": "€", + "name": "Euro" + }, + { + "code": "GMD", + "local": "Gambia", + "symbol": "D", + "name": "dalasi" + }, + { + "code": "NGN", + "local": "Nigeria", + "symbol": "₦", + "name": "Nigerian naira" + }, + { + "code": "BSD", + "local": "Bahamas", + "symbol": "$", + "name": "Bahamian dollar" + }, + { + "code": "USD", + "local": "Bahamas", + "symbol": "$", + "name": "United States dollar" }, { "code": "EUR", @@ -1542,46 +1398,136 @@ "name": "Kuwaiti dinar" }, { - "code": "TWD", - "local": "Taiwan", - "symbol": "$", - "name": "New Taiwan dollar" + "code": "MVR", + "local": "Maldives", + "symbol": ".ރ", + "name": "Maldivian rufiyaa" }, { - "code": "BIF", - "local": "Burundi", + "code": "SSP", + "local": "South Sudan", + "symbol": "£", + "name": "South Sudanese pound" + }, + { + "code": "IRR", + "local": "Iran", + "symbol": "﷼", + "name": "Iranian rial" + }, + { + "code": "ALL", + "local": "Albania", + "symbol": "L", + "name": "Albanian lek" + }, + { + "code": "BRL", + "local": "Brazil", + "symbol": "R$", + "name": "Brazilian real" + }, + { + "code": "RSD", + "local": "Serbia", + "symbol": "дин.", + "name": "Serbian dinar" + }, + { + "code": "BZD", + "local": "Belize", + "symbol": "$", + "name": "Belize dollar" + }, + { + "code": "MMK", + "local": "Myanmar", + "symbol": "Ks", + "name": "Burmese kyat" + }, + { + "code": "BTN", + "local": "Bhutan", + "symbol": "Nu.", + "name": "Bhutanese ngultrum" + }, + { + "code": "INR", + "local": "Bhutan", + "symbol": "₹", + "name": "Indian rupee" + }, + { + "code": "VES", + "local": "Venezuela", + "symbol": "Bs.S.", + "name": "Venezuelan bolívar soberano" + }, + { + "code": "LRD", + "local": "Liberia", + "symbol": "$", + "name": "Liberian dollar" + }, + { + "code": "JMD", + "local": "Jamaica", + "symbol": "$", + "name": "Jamaican dollar" + }, + { + "code": "PLN", + "local": "Poland", + "symbol": "zł", + "name": "Polish złoty" + }, + { + "code": "KYD", + "local": "Cayman Islands", + "symbol": "$", + "name": "Cayman Islands dollar" + }, + { + "code": "BND", + "local": "Brunei", + "symbol": "$", + "name": "Brunei dollar" + }, + { + "code": "SGD", + "local": "Brunei", + "symbol": "$", + "name": "Singapore dollar" + }, + { + "code": "KMF", + "local": "Comoros", "symbol": "Fr", - "name": "Burundian franc" + "name": "Comorian franc" }, { "code": "USD", - "local": "American Samoa", + "local": "Guam", "symbol": "$", "name": "United States dollar" }, { - "code": "BGN", - "local": "Bulgaria", - "symbol": "лв", - "name": "Bulgarian lev" + "code": "TOP", + "local": "Tonga", + "symbol": "T$", + "name": "Tongan paʻanga" }, { - "code": "ZAR", - "local": "South Africa", - "symbol": "R", - "name": "South African rand" + "code": "AUD", + "local": "Kiribati", + "symbol": "$", + "name": "Australian dollar" }, { - "code": "PEN", - "local": "Peru", - "symbol": "S/ ", - "name": "Peruvian sol" - }, - { - "code": "AWG", - "local": "Aruba", - "symbol": "ƒ", - "name": "Aruban florin" + "code": "KID", + "local": "Kiribati", + "symbol": "$", + "name": "Kiribati dollar" }, { "code": "GHS", @@ -1589,6 +1535,18 @@ "symbol": "₵", "name": "Ghanaian cedi" }, + { + "code": "XAF", + "local": "Chad", + "symbol": "Fr", + "name": "Central African CFA franc" + }, + { + "code": "ZWL", + "local": "Zimbabwe", + "symbol": "$", + "name": "Zimbabwean dollar" + }, { "code": "EUR", "local": "Saint Martin", @@ -1596,15 +1554,57 @@ "name": "Euro" }, { - "code": "INR", - "local": "India", - "symbol": "₹", - "name": "Indian rupee" + "code": "MNT", + "local": "Mongolia", + "symbol": "₮", + "name": "Mongolian tögrög" }, { - "code": "UGX", - "local": "Uganda", - "symbol": "Sh", - "name": "Ugandan shilling" + "code": "EUR", + "local": "Portugal", + "symbol": "€", + "name": "Euro" + }, + { + "code": "USD", + "local": "American Samoa", + "symbol": "$", + "name": "United States dollar" + }, + { + "code": "XAF", + "local": "Republic of the Congo", + "symbol": "Fr", + "name": "Central African CFA franc" + }, + { + "code": "EUR", + "local": "Belgium", + "symbol": "€", + "name": "Euro" + }, + { + "code": "ILS", + "local": "Israel", + "symbol": "₪", + "name": "Israeli new shekel" + }, + { + "code": "NZD", + "local": "New Zealand", + "symbol": "$", + "name": "New Zealand dollar" + }, + { + "code": "NIO", + "local": "Nicaragua", + "symbol": "C$", + "name": "Nicaraguan córdoba" + }, + { + "code": "XCD", + "local": "Anguilla", + "symbol": "$", + "name": "Eastern Caribbean dollar" } ] \ No newline at end of file From 3bf1e50620d4310bfff5e70b60ab73bc6392c317 Mon Sep 17 00:00:00 2001 From: Matt Kilgore Date: Sun, 21 Jul 2024 10:40:03 -0400 Subject: [PATCH 4/6] Splitting dependencies into separate docker layers (better caching) (#142) * Initial test with NodeJS * Fix screw up * Try again * Try Golang caching * Test with some more cache --- .../workflows/docker-publish-rootless.yaml | 4 +-- .github/workflows/docker-publish.yaml | 4 +-- Dockerfile | 19 +++++++++++--- Dockerfile.rootless | 25 ++++++++++++------- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/.github/workflows/docker-publish-rootless.yaml b/.github/workflows/docker-publish-rootless.yaml index 8b330cd6..d4726a7e 100644 --- a/.github/workflows/docker-publish-rootless.yaml +++ b/.github/workflows/docker-publish-rootless.yaml @@ -92,8 +92,8 @@ jobs: tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} platforms: linux/amd64,linux/arm64,linux/arm/v7 -# cache-from: type=gha -# cache-to: type=gha,mode=max + cache-from: type=gha + cache-to: type=gha,mode=max build-args: | VERSION=${{ github.ref_name }} COMMIT=${{ github.sha }} diff --git a/.github/workflows/docker-publish.yaml b/.github/workflows/docker-publish.yaml index 8b63be01..4e4dbe78 100644 --- a/.github/workflows/docker-publish.yaml +++ b/.github/workflows/docker-publish.yaml @@ -89,8 +89,8 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64,linux/arm64,linux/arm/v7 -# cache-from: type=gha -# cache-to: type=gha,mode=max + cache-from: type=gha + cache-to: type=gha,mode=max build-args: | VERSION=${{ github.ref_name }} COMMIT=${{ github.sha }} diff --git a/Dockerfile b/Dockerfile index a32d56a2..85097bd7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,23 @@ +# Node dependencies +FROM node:18-alpine AS frontend-dependencies +WORKDIR /app +RUN npm install -g pnpm +COPY frontend/package.json frontend/pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile --shamefully-hoist # Build Nuxt FROM node:18-alpine AS frontend-builder WORKDIR /app RUN npm install -g pnpm -COPY frontend/package.json frontend/pnpm-lock.yaml ./ -RUN pnpm install --frozen-lockfile --shamefully-hoist COPY frontend . +COPY --from=frontend-dependencies /app/node_modules ./node_modules RUN pnpm build +FROM golang:alpine AS builder-dependencies +WORKDIR /go/src/app +COPY ./backend . +RUN go mod download + # Build API FROM golang:alpine AS builder ARG BUILD_TIME @@ -19,10 +29,11 @@ RUN apk update && \ WORKDIR /go/src/app COPY ./backend . -RUN go get -d -v ./... RUN rm -rf ./app/api/public COPY --from=frontend-builder /app/.output/public ./app/api/static/public -RUN CGO_ENABLED=0 GOOS=linux go build \ +COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod +RUN --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=linux go build \ -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ -o /go/bin/api \ -v ./app/api/*.go diff --git a/Dockerfile.rootless b/Dockerfile.rootless index aa7e6186..3a0799d8 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,35 +1,42 @@ +# Node dependencies +FROM node:18-alpine AS frontend-dependencies +WORKDIR /app +RUN npm install -g pnpm +COPY frontend/package.json frontend/pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile --shamefully-hoist # Build Nuxt FROM node:18-alpine AS frontend-builder WORKDIR /app RUN npm install -g pnpm -COPY frontend/package.json frontend/pnpm-lock.yaml ./ -RUN pnpm install --frozen-lockfile --shamefully-hoist COPY frontend . +COPY --from=frontend-dependencies /app/node_modules ./node_modules RUN pnpm build +FROM golang:alpine AS builder-dependencies +WORKDIR /go/src/app +COPY ./backend . +RUN go mod download + # Build API FROM golang:alpine AS builder ARG BUILD_TIME ARG COMMIT ARG VERSION -ARG BUSYBOX_VERSION=1.36.1-r31 RUN apk update && \ apk upgrade && \ apk add --update git build-base gcc g++ WORKDIR /go/src/app COPY ./backend . -RUN go get -d -v ./... RUN rm -rf ./app/api/public COPY --from=frontend-builder /app/.output/public ./app/api/static/public -RUN CGO_ENABLED=0 GOOS=linux go build \ +COPY --from=builder-dependencies /go/pkg/mod /go/pkg/mod +RUN --mount=type=cache,target=/root/.cache/go-build \ + CGO_ENABLED=0 GOOS=linux go build \ -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ -o /go/bin/api \ - -v ./app/api/*.go && \ - chmod +x /go/bin/api && \ - # create a directory so that we can copy it in the next stage - mkdir /data + -v ./app/api/*.go FROM gcr.io/distroless/java:latest From e05135207008c1a930166d517e82b971c9e199e3 Mon Sep 17 00:00:00 2001 From: Matt Kilgore Date: Sat, 27 Jul 2024 09:10:47 -0400 Subject: [PATCH 5/6] chore: update openapi documentation (#148) --- docs/docs/api/openapi-2.0.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/api/openapi-2.0.json b/docs/docs/api/openapi-2.0.json index d517beac..2b695bc5 100644 --- a/docs/docs/api/openapi-2.0.json +++ b/docs/docs/api/openapi-2.0.json @@ -1683,12 +1683,14 @@ "parameters": [ { "type": "string", + "example": "admin@admin.com", "description": "string", "name": "username", "in": "formData" }, { "type": "string", + "example": "admin", "description": "string", "name": "password", "in": "formData" From 2ab276653406d01cce5cd4d857b017e46b735af0 Mon Sep 17 00:00:00 2001 From: Victor Hooi Date: Sun, 28 Jul 2024 00:56:49 +1000 Subject: [PATCH 6/6] Fix small typo in label discussion thread URL --- frontend/pages/reports/label-generator.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/reports/label-generator.vue b/frontend/pages/reports/label-generator.vue index e7281bf4..552e35f7 100644 --- a/frontend/pages/reports/label-generator.vue +++ b/frontend/pages/reports/label-generator.vue @@ -308,7 +308,7 @@

This feature is in early development stages and may change in future releases, if you have feedback please - provide it in the GitHub Discussion + provide it in the GitHub Discussion

Tips