Files
WPS3Media/ui/components/SettingsPanelOption.svelte
Malin 3248cbb029 feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)
Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.

Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
  - Provider key: s3compatible
  - Reads user-configured endpoint URL from settings
  - Uses path-style URL access (required by most S3-compatible services)
  - Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
    AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
  - Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
2026-03-03 12:30:18 +01:00

153 lines
3.8 KiB
Svelte

<script>
import {getContext, hasContext} from "svelte";
import {writable} from "svelte/store";
import {slide} from "svelte/transition";
import {defined_settings, validationErrors} from "../js/stores";
import PanelRow from "./PanelRow.svelte";
import ToggleSwitch from "./ToggleSwitch.svelte";
import DefinedInWPConfig from "./DefinedInWPConfig.svelte";
import SettingNotifications from "./SettingNotifications.svelte";
export let heading = "";
export let description = "";
export let placeholder = "";
export let nested = false;
export let first = false; // of nested items
// Toggle and Text may both be used at same time.
export let toggleName = "";
export let toggle = false;
export let textName = "";
export let text = "";
export let alwaysShowText = false;
export let definedSettings = defined_settings;
/**
* Optional validator function.
*
* @param {string} textValue
*
* @return {string} Empty if no error
*/
export let validator = ( textValue ) => "";
// Parent page may want to be locked.
let settingsLocked = writable( false );
let textDirty = false;
if ( hasContext( "settingsLocked" ) ) {
settingsLocked = getContext( "settingsLocked" );
}
$: locked = $settingsLocked;
$: toggleDisabled = $definedSettings.includes( toggleName ) || locked;
$: textDisabled = $definedSettings.includes( textName ) || locked;
$: input = ((toggleName && toggle) || !toggleName || alwaysShowText) && textName;
$: headingName = input ? textName + "-heading" : toggleName;
/**
* Validate the text if validator function supplied.
*
* @param {string} text
* @param {bool} toggle
*
* @return {string}
*/
function validateText( text, toggle ) {
let message = "";
if ( validator !== undefined && toggle && !textDisabled ) {
message = validator( text );
}
validationErrors.update( _validationErrors => {
if ( _validationErrors.has( textName ) && message === "" ) {
_validationErrors.delete( textName );
} else if ( message !== "" ) {
_validationErrors.set( textName, message );
}
return _validationErrors;
} );
return message;
}
function onTextInput() {
textDirty = true;
}
$: validationError = validateText( text, toggle );
/**
* If appropriate, clicking the header toggles to toggle switch.
*/
function headingClickHandler() {
if ( toggleName && !toggleDisabled ) {
toggle = !toggle;
}
}
</script>
<div class="setting" class:nested class:first>
<PanelRow class="option">
{#if toggleName}
<ToggleSwitch name={toggleName} bind:checked={toggle} disabled={toggleDisabled}>
{heading}
</ToggleSwitch>
<!-- TODO: Fix a11y. -->
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<h4 id={headingName} on:click={headingClickHandler} class="toggler" class:toggleDisabled>{heading}</h4>
{:else}
<h4 id={headingName}>{heading}</h4>
{/if}
<DefinedInWPConfig defined={$definedSettings.includes( toggleName ) || (input && $definedSettings.includes( textName ))}/>
</PanelRow>
<PanelRow class="desc">
<p>{@html description}</p>
</PanelRow>
{#if input}
<PanelRow class="input">
<input
type="text"
id={textName}
name={textName}
bind:value={text}
on:input={onTextInput}
minlength="1"
size="10"
{placeholder}
disabled={textDisabled}
class:disabled={textDisabled}
aria-labelledby={headingName}
>
<label for={textName}>
{heading}
</label>
</PanelRow>
{#if validationError && textDirty}
<p class="input-error" transition:slide>{validationError}</p>
{/if}
{/if}
{#if toggleName}
<SettingNotifications settingKey={toggleName}/>
{/if}
{#if textName}
<SettingNotifications settingKey={textName}/>
{/if}
<slot/>
</div>
<style>
.toggler:not(.toggleDisabled) {
cursor: pointer;
}
</style>