Skip to content

feat(theme): core color schemes and backgrounds, account settings tab cleanup - #3945

Merged
marcelfolaron merged 10 commits into
masterfrom
feat/core-theme-backgrounds
Oct 18, 2026
Merged

marcelfolaron merged 10 commits into
masterfrom
feat/core-theme-backgrounds

Conversation

@marcelfolaron

@marcelfolaron marcelfolaron commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Moves the ThemeBundle plugin's features into core:

  • Color schemes: 11 more schemes (Copper, Mustard, Nebula, Fuchsia, Fruit, Highlands, Moss, Morning, Ocean, Energy, Forest) in Theme::$colorSchemes. The keys are unchanged, so schemes users picked through the plugin still apply.
  • Background tab in the user's own settings, plus a "Background" link in the user menu. Users pick the color gradient, upload an image or choose an Unsplash photo. Each change saves at once and swaps the page background in place (out-of-band swap of #backgroundImageSetter), with no reload.
  • Unsplash only when configured: set LEAN_UNSPLASH_ACCESS_KEY (documented in config/sample.env). There is no built-in key. Without one the tab offers uploads only.

Changes compared with the plugin

  • Photos are resolved on the server by their Unsplash id. The plugin accepted any URL from the browser, stored it and printed it into inline JS (updateBg('…') with FILTER_SANITIZE_URL, which keeps quotes). Only https://images.unsplash.com URLs are stored now.
  • Unsplash API guidelines: results credit the photographer with referral links, and choosing a photo reports the download (download_location).
  • Uploads must be real JPG/PNG/GIF/WebP images (extension + getimagesize). SVG is refused. The file is stored in the owner-restricted user module. A failed upload no longer crashes on the error string Files::upload() returns.
  • The header's background <style> moved to sections.backgroundStyle, so the tab reuses the same CSS for the swap.
  • The plugin's "Save settings" button only showed a toast and is gone, since every change already saves.

Code

  • app/Domain/Users/Services/Backgrounds.php: background type, Unsplash search/selection, upload. Uses Laravel's HTTP client Factory through DI (no facade).
  • app/Domain/Users/Hxcontrollers/Background.php + users::partials.background: the tab, with current-background and unsplash-results fragments.
  • Strings translated into all 43 languages. Arabic, Persian, kaa, ks-IN and km-KH would benefit from a native review.

Account settings tabs

Tabs are now: Profile, Security, Settings, Notifications, Webhooks, Theme, Background, plugin tabs, Personal Access Tokens (always last).

  • Webhooks tab: the personal webhook moved out of the Notifications tab into its own tab and form. Users::saveOwnWebhookSettings() (@api) saves it, and saveOwnNotificationPreferences() no longer touches the webhook. API clients that sent webhook fields along with the notification preferences must call the new method (no compatibility path).
  • Personal Access Tokens: the page renders this tab after @dispatchEvent('tabs') instead of an Auth listener injecting it, so plugin tabs can't push it out of last place. The ShowPersonalToken* listeners are removed.
  • Fix: clearing the webhook URL never worked. ConvertEmptyStringsToNull turns the emptied field into null, which was rejected as an invalid URL. A missing or null URL now clears the webhook.
  • The webhook description pointed to the settings "above"; it now names the Notifications tab (all languages).

Follow-ups (not in this PR)

  • Remove ThemeBundle from the plugins repo, otherwise installs with both get two Background tabs.
  • Rotate the Unsplash key that was hardcoded in the plugin's Config/UnsplashConfig.php, and set the new one as LEAN_UNSPLASH_ACCESS_KEY on Cloud. The free demo tier allows 50 requests/hour.

Test plan

  • New unit tests tests/Unit/app/Domain/Users/Services/BackgroundsTest.php (8 tests): no key → Unsplash off and no requests; search mapping + auth header; failure → empty; photo selection stores the resized URL and reports the download; non-Unsplash host refused; bad photo id refused without a request; unknown type refused; fake image upload refused.
  • Existing ThemeTest, HeaderCssStringTest, EditOwnTest, OnboardingServiceTest and UsersServiceTest pass. Pint and PHPStan are clean on the changed files.
  • In the browser (worktree site), without a key: only upload is shown; gradient, upload, fake-image rejection; the background persists across pages.
  • In the browser, with a key: initial wallpapers, search, attribution, photo selection applied live, Unsplash/Upload toggle.
  • Theme tab lists all 15 schemes; the user menu shows the Background link.
  • Webhook tests moved to saveOwnWebhookSettings(), plus new tests: notification preferences never touch the webhook; a null URL clears it; the controller routes savewebhooks to #webhooks.
  • In the browser: tab order; Webhooks tab rejects an http URL, saves an https one, and clearing the URL works; saving Notifications leaves the webhook unchanged; Personal Access Tokens tab loads.

🤖 Generated with Claude Code

… core

The ThemeBundle plugin's features are now part of core:

- 11 more color schemes (Copper, Mustard, Nebula, ...). Their keys are
  unchanged, so schemes users picked through the plugin still apply.
- A Background tab in the user's own settings (and a user menu link):
  the color gradient, an uploaded image or an Unsplash photo. Every
  change saves right away and swaps the page background in place.
- Unsplash is only offered when LEAN_UNSPLASH_ACCESS_KEY is set. There is
  no built-in key; without one the tab offers uploads only.

Changes from the plugin:
- Photos are resolved on the server by their Unsplash id, so a client can
  no longer store an arbitrary URL as background (the plugin printed it
  into inline JS). Selecting a photo reports the download to Unsplash and
  results credit the photographer, as the Unsplash API guidelines require.
- Uploads must be JPG, PNG, GIF or WebP images (SVG is refused), and a
  failed upload no longer crashes on the error string Files::upload returns.
- The header's background <style> moved to sections.backgroundStyle so the
  tab reuses it for the out-of-band swap.

Strings are translated into all 43 languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 14:46
@marcelfolaron
marcelfolaron requested a review from a team as a code owner October 18, 2026 14:46
@marcelfolaron
marcelfolaron requested review from broskees and removed request for a team October 18, 2026 14:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

GET-based background changes allow cross-site preference resets, and accessibility, refresh behavior, and image-format validation need correction.

4 open issues
What changed in this PR

Moves ThemeBundle’s color schemes and background customization into Leantime core.

Changes:

  • Adds 11 color schemes while preserving existing scheme keys.
  • Adds live background selection through uploads or configured Unsplash access.
  • Adds translations, shared background styling, and service tests.
File Description
tests/​Unit/​app/​Domain/​Users/​Services/​BackgroundsTest.php Tests background service behavior and validation.
config/​sample.env Documents the Unsplash access key.
app/​Views/​Templates/​sections/​header.blade.php Uses shared background styling.
app/​Views/​Templates/​sections/​backgroundStyle.blade.php Provides reusable, live-swappable background CSS.
app/​Language/​zh-TW.ini Adds Traditional Chinese background strings.
app/​Language/​zh-CN.ini Adds Simplified Chinese background strings.
app/​Language/​vi-VN.ini Adds Vietnamese background strings.
app/​Language/​uk-UA.ini Adds Ukrainian background strings.
app/​Language/​tr-TR.ini Adds Turkish background strings.
app/​Language/​sv-SE.ini Adds Swedish background strings.
app/​Language/​sr-SP.ini Adds Serbian background strings.
app/​Language/​sl-SI.ini Adds Slovenian background strings.
app/​Language/​sk-SK.ini Adds Slovak background strings.
app/​Language/​ru-RU.ini Adds Russian background strings.
app/​Language/​ro-RO.ini Adds Romanian background strings.
app/​Language/​pt-PT.ini Adds Portuguese background strings.
app/​Language/​pt-BR.ini Adds Brazilian Portuguese background strings.
app/​Language/​pl-PL.ini Adds Polish background strings.
app/​Language/​no-NO.ini Adds Norwegian background strings.
app/​Language/​nl-NL.ini Adds Dutch background strings.
app/​Language/​lv-LV.ini Adds Latvian background strings.
app/​Language/​ks-IN.ini Adds Kashmiri background strings.
app/​Language/​ko-KR.ini Adds Korean background strings.
app/​Language/​km-KH.ini Adds Khmer background strings.
app/​Language/​kaa.ini Adds Karakalpak background strings.
app/​Language/​ja-JP.ini Adds Japanese background strings.
app/​Language/​it-IT.ini Adds Italian background strings.
app/​Language/​is-IS.ini Adds Icelandic background strings.
app/​Language/​id-ID.ini Adds Indonesian background strings.
app/​Language/​hu-HU.ini Adds Hungarian background strings.
app/​Language/​hr-HR.ini Adds Croatian background strings.
app/​Language/​he-IL.ini Adds Hebrew background strings.
app/​Language/​fr-FR.ini Adds French background strings.
app/​Language/​fr-CH.ini Adds Swiss French background strings.
app/​Language/​fa-IR.ini Adds Persian background strings.
app/​Language/​et-EE.ini Adds Estonian background strings.
app/​Language/​es-MX.ini Adds Mexican Spanish background strings.
app/​Language/​es-ES.ini Adds Spanish background strings.
app/​Language/​es-419.ini Adds Latin American Spanish background strings.
app/​Language/​en-US.ini Adds US English background strings.
app/​Language/​en-GB.ini Adds British English background strings.
app/​Language/​el-GR.ini Adds Greek background strings.
app/​Language/​de-DE.ini Adds German background strings.
app/​Language/​de-DE-inf.ini Adds informal German background strings.
app/​Language/​de-CH.ini Adds Swiss German background strings.
app/​Language/​da-DK.ini Adds Danish background strings.
app/​Language/​cs-CZ.ini Adds Czech background strings.
app/​Language/​ar-SA.ini Adds Arabic background strings.
app/​Domain/​Users/​Templates/​partials/​background.blade.php Adds background controls, uploads, and photo results.
app/​Domain/​Users/​Templates/​editOwn.blade.php Adds the Background settings tab.
app/​Domain/​Users/​Services/​Backgrounds.php Handles preferences, uploads, and Unsplash integration.
app/​Domain/​Users/​Hxcontrollers/​Background.php Handles background requests and fragment responses.
app/​Domain/​Auth/​Templates/​partials/​loginInfo.blade.php Adds the Background menu link.
app/​Core/​UI/​Theme.php Adds 11 color schemes.
app/​Core/​Configuration/​DefaultConfig.php Defines optional Unsplash configuration.

Review effort: Balanced

Comment thread app/Domain/Users/Hxcontrollers/Background.php Outdated
Comment thread app/Domain/Users/Services/Backgrounds.php Outdated
Comment thread app/Domain/Users/Templates/partials/background.blade.php Outdated
Comment thread app/Domain/Users/Templates/partials/background.blade.php
…last

Account settings tabs are now: Profile, Security, Settings, Notifications,
Webhooks, Theme, Background, plugin tabs, Personal Access Tokens.

- The personal webhook moves out of the Notifications tab into a Webhooks
  tab with its own form. Users::saveOwnWebhookSettings() saves it;
  saveOwnNotificationPreferences() no longer touches the webhook.
- The Personal Access Tokens tab is rendered by the page after the plugin
  tabs instead of through an Auth event listener, so it is always last.
  The two listener classes are gone.
- Clearing the webhook URL works again: ConvertEmptyStringsToNull turns the
  emptied field into null, which was rejected as an invalid URL. A missing
  or null URL now clears the webhook.
- The webhook description pointed to the settings "above"; it now names
  the Notifications tab (all languages).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 14:56
@marcelfolaron marcelfolaron changed the title feat(theme): bring the ThemeBundle color schemes and backgrounds into core feat(theme): core color schemes and backgrounds, account settings tab cleanup Oct 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Eager background loading consumes shared Unsplash quota during unrelated account-settings visits.

5 open issues

Review effort: Balanced

Comment thread app/Domain/Users/Templates/editOwn.blade.php Outdated
- Background changes (type, Unsplash photo, upload) only act on POST and
  read the type from the body. The Frontcontroller dispatches GET to these
  actions too and the origin check skips GET, so a cross-site link could
  reset a user's background.
- Uploads are checked by the detected image type too: getimagesize() also
  recognizes TIFF, BMP and others, which browsers can't show.
- The gradient/image tiles are native buttons with aria-pressed, so the
  choice works with the keyboard (global::selectable is mouse-only).
- "Show other images" asks for the next page of a typed search instead of
  the same results; typing a new query starts at page 1 again.
- The Background tab loads when it is shown (intersect once), so visits to
  other account settings tabs no longer query Unsplash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Upload lifecycle and theme accessibility concerns remain unresolved, and the external API and live-update integration need final human validation.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Improve primary-button contrast in Ocean, Nebula, and Energy themes

app/​Core/​UI/​Theme.php:160

Ocean, Nebula, and Energy give white primary-button labels contrast ratios of only 1.85:1, 2.89:1, and 2.97:1 respectively, below the 4.5:1 requirement for normal text. Both built-in themes keep --accent1-color white, and public/assets/css/components/forms.css:376–385 uses it through --main-action-color on the accent background. This makes actions such as Save and Upload difficult to read; the navigation scrim does not cover these buttons. Provide a contrasting action foreground or darker action background for these schemes.

Medium severity Replace background uploads without deleting obsolete files

app/​Domain/​Users/​Services/​Backgrounds.php:213

Each background upload creates a new file and database row, but replacing it with another upload, an Unsplash photo, or the gradient never removes the old file. The theme only replaces or clears the saved URL, so repeated changes accumulate unused storage. Track the background upload's file ID and delete that specific file after a replacement is successfully saved. Do not delete all files in the user module, which also holds profile pictures.

5 resolved since last review

Review effort: Balanced

…kground uploads

- Ocean, Nebula and Energy primaries are darkened (same hue) so white
  button labels reach WCAG AA (1.85/2.89/2.97:1 -> 4.6:1).
- The uploaded background's file id is stored per user; when another
  upload, an Unsplash photo or the gradient replaces it, that one file is
  deleted. Other "user" module files (profile pictures) are never touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@marcelfolaron

Copy link
Copy Markdown
Collaborator Author

Addressed the two issues from the latest Copilot review summary (they had no inline threads to resolve) in db4bfd4:

  • Contrast: Ocean, Nebula and Energy primaries darkened with the same hue so white button labels pass AA: #73ccd5 → #298089, #d18475 → #bf5440, #FA6821 → #cf4705 (all ≈4.6:1). I didn't flip --accent1-color to dark text globally, because --main-action-color derives from it and is also used on dark, non-accent backgrounds (e.g. project avatars).
  • Upload lifecycle: the background's uploaded file id is stored in usersettings.{id}.backgroundFileId. A new upload, an Unsplash photo or the gradient deletes that one file via Files::deleteFile(); other user module files (profile pictures) are untouched. New unit tests cover all three replacements, and it was verified against the dev DB.

Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Background cleanup can break saved images, and Forest has unreadable dark-mode text contrast.

2 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Forest theme has unreadable dark-mode text contrast

app/​Core/​UI/​Theme.php:170

Forest uses #74211c unchanged in dark mode because getColorSchemeForMode() only adjusts grayscale schemes. Both built-in dark themes use this as the active-project text color on #404040 (nav.css:644–648), giving approximately 1.02:1 contrast. Global links also use this primary color. Add a readable dark-mode variant through getColorSchemeForMode(), preserving the forrest key and meeting text contrast requirements.

Review effort: Balanced

Comment thread app/Domain/Users/Services/Backgrounds.php
Comment thread app/Domain/Users/Services/Backgrounds.php
Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:43
…in dark mode

- Background uploads get a unique stored name. With
  LEAN_FILESYSTEM_RENAME_FILES=false files keep their own name, so two
  uploads of the same file shared one stored file and deleting the
  replaced upload deleted the new background.
- The background type and image are read from the settings cache on every
  request instead of a session copy, so a change (and the deleted upload)
  made in another session shows up there too. Saves already invalidate
  that cache.
- Forest gets a dark-mode variant (#db7069 / #ac8874): its near-black red
  was 1.0:1 on dark panels; the lighter red keeps 3.2:1 on #404040 and
  under white button labels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved accessibility issues affect dark-mode text readability and identification of the background upload control.

2 open issues
2 resolved since last review

Review effort: Balanced

Comment thread app/Core/UI/Theme.php
Comment thread app/Domain/Users/Templates/partials/background.blade.php Outdated
Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:49
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Background uploads have retrieval and concurrency defects, and Forest’s dark-mode button labels have insufficient contrast.

3 open issues
2 resolved since last review

Review effort: Balanced

Comment thread app/Domain/Users/Services/Backgrounds.php Outdated
Comment thread app/Domain/Users/Services/Backgrounds.php Outdated
Comment thread app/Core/UI/Theme.php Outdated
Copilot AI balanced review requested due to automatic review settings October 18, 2026 15:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Generated background filenames are incompatible with download lookup when filesystem renaming is disabled, causing uploaded images to return 404.

3 open issues

Review effort: Balanced

…ckground cleanup

- Primary buttons get --main-action-label-color: where the white label is
  below AA on the first accent and dark text reads better, the header sets
  it to #1a1a1a (Forest in dark mode: 3.2:1 -> 5.6:1). Other uses of
  --main-action-color are unchanged.
- Background uploads are named background{16 hex}: files/get strips
  everything but letters and digits from the name before the lookup, so
  the hyphenated name returned 404 when file renaming is off.
- The tracked upload stores its URL too, and the previous upload is only
  deleted when it is not the background that ended up saved, so two
  changes racing in two tabs can never delete the image in use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Concurrent cleanup can delete the selected background, and dark-mode contrast corrections remain incomplete.

2 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Light-mode palette accents lack dark-mode contrast

app/​Core/​UI/​Theme.php:120

The ten new palettes other than Forest keep their light-mode accents in dark mode. Active dropdown labels use the primary accent on #404040 (public/theme/default/css/dark.css:26,73–74 and public/assets/css/components/dropdowns.css:704–708). Contrast ranges from 1.43:1 for Copper to only 2.25:1, making these labels difficult to read. Provide contrasting dark-mode variants or a separate accessible text color. The new button-label token does not affect dropdown text.

3 resolved since last review

Review effort: Balanced

Comment thread app/Domain/Users/Services/Backgrounds.php Outdated
Comment thread app/Views/Templates/sections/header.blade.php
…ttes, contrast-aware preview

- Background changes (gradient, Unsplash photo, upload) save, track the
  uploaded file and delete the replaced one under a per-user cache lock,
  so two tabs can't delete the upload that ends up in use. The URL guard
  is gone; it compared against request-local cached settings. A change
  that can't get the lock within 10s reports "not saved" and removes its
  fresh upload. Unsplash lookups and file storage stay outside the lock.
- All eleven added palettes get dark-mode colors that reach ~4.6:1 as text
  on #404040 (active menu/dropdown items, links); their primary buttons
  get the dark label (#1a1a1a, ~7.8:1). The dark-mode overrides, grayscale
  included, are one table.
- The theme tab's live preview (snippets.toggleColors) applies the same
  contrast rules as the header: nav scrim and dark button label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 18, 2026 16:18
@marcelfolaron

Copy link
Copy Markdown
Collaborator Author

Addressed the remaining summary issue (light-mode accents in dark mode) in 8a6f922: all eleven added palettes now have dark-mode colors that reach ~4.6:1 as text on #404040 (active menu/dropdown items, links). Their primary buttons switch to the dark label (~7.8:1) through --main-action-label-color. The dark-mode overrides, grayscale included, are now one table (Theme::DARK_MODE_COLOR_SCHEMES). This replaces the 3:1 compromise from my earlier comment. The default Leantime/company colors are unchanged in dark mode; that's an existing limitation outside this PR.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Response ordering remains unresolved, and background file cleanup and live updates need final integration review.

No open issues 🎉

1 previously missed issue

In code that hasn't changed since last review

Medium severity Serialize picker requests to prevent stale responses overwriting selections

app/​Domain/​Users/​Templates/​partials/​background.blade.php:9

Serialize requests across this picker, not just each individual button. Selecting a photo saves its URL and releases the server lock before waiting for Unsplash download tracking. During that wait, clicking the gradient can save and display the gradient. The photo response can then arrive last with its request-local cached image and restore that image on screen, although the saved preference is gradient. A shared HTMX request queue keeps these responses ordered; aborting a request alone would not stop its server-side writes.

2 resolved since last review

Review effort: Balanced

The gradient button, photo buttons and upload form sync on
#backgroundPicker with "drop": clicks while a change is running are
ignored, so a slower response can no longer repaint a background the user
already replaced. "queue" lost them instead, because the response replaces
the gradient button and htmx drops queued requests of removed elements.
While a change runs the picker dims the current background and shows a
progress cursor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@marcelfolaron

Copy link
Copy Markdown
Collaborator Author

Addressed the summary issue "Serialize picker requests" in ed08fd8. The gradient button, photo buttons and upload form share hx-sync="#backgroundPicker:drop", so only one background change runs at a time and a slower response can't repaint a background the user already replaced. While it runs, the picker dims the current background and shows a progress cursor (hx-indicator="#backgroundPicker").

I used drop rather than queue on purpose. Each response replaces #currentBackground, including the gradient button, and htmx discards queued requests whose element was removed. With queue, the gradient click was silently lost (verified in the browser).

Verified: clicking a photo and then immediately the gradient runs only the photo request; screen and saved setting both show the photo; a later gradient click works normally.

@marcelfolaron
marcelfolaron merged commit d5b5348 into master Oct 18, 2026
12 checks passed
@marcelfolaron
marcelfolaron deleted the feat/core-theme-backgrounds branch October 18, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants