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
This commit is contained in:
139
ui/components/Panel.svelte
Normal file
139
ui/components/Panel.svelte
Normal file
@@ -0,0 +1,139 @@
|
||||
<script>
|
||||
import {createEventDispatcher, getContext, hasContext} from "svelte";
|
||||
import {writable} from "svelte/store";
|
||||
import {fade} from "svelte/transition";
|
||||
import {link} from "svelte-spa-router";
|
||||
import {defined_settings, strings} from "../js/stores";
|
||||
import PanelContainer from "./PanelContainer.svelte";
|
||||
import PanelRow from "./PanelRow.svelte";
|
||||
import DefinedInWPConfig from "./DefinedInWPConfig.svelte";
|
||||
import ToggleSwitch from "./ToggleSwitch.svelte";
|
||||
import HelpButton from "./HelpButton.svelte";
|
||||
import Button from "./Button.svelte";
|
||||
|
||||
const classes = $$props.class ? $$props.class : "";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let ref = {};
|
||||
export let name = "";
|
||||
export let heading = "";
|
||||
export let defined = false;
|
||||
export let multi = false;
|
||||
export let flyout = false;
|
||||
export let toggleName = "";
|
||||
export let toggle = false;
|
||||
export let refresh = false;
|
||||
export let refreshText = $strings.refresh_title;
|
||||
export let refreshDesc = refreshText;
|
||||
export let refreshing = false;
|
||||
export let helpKey = "";
|
||||
export let helpURL = "";
|
||||
export let helpDesc = $strings.help_desc;
|
||||
|
||||
// We can display storage provider info on the right-hand side of the panel's header.
|
||||
// In the future, if anything else needs to be displayed in the same position we
|
||||
// should create a named slot or assignable component. CSS changes would be required.
|
||||
export let storageProvider = null;
|
||||
|
||||
// Parent page may want to be locked.
|
||||
let settingsLocked = writable( false );
|
||||
|
||||
if ( hasContext( "settingsLocked" ) ) {
|
||||
settingsLocked = getContext( "settingsLocked" );
|
||||
}
|
||||
|
||||
$: locked = $settingsLocked;
|
||||
$: toggleDisabled = $defined_settings.includes( toggleName ) || locked;
|
||||
|
||||
/**
|
||||
* If appropriate, clicking the header toggles to toggle switch.
|
||||
*/
|
||||
function headingClickHandler() {
|
||||
if ( toggleName && !toggleDisabled ) {
|
||||
toggle = !toggle;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch escape key and emit a custom cancel event.
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
function handleKeyup( event ) {
|
||||
if ( event.key === "Escape" ) {
|
||||
event.preventDefault();
|
||||
dispatch( "cancel" );
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- TODO: Fix a11y. -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="panel {name}"
|
||||
class:multi
|
||||
class:flyout
|
||||
class:locked
|
||||
transition:fade={{duration: flyout ? 200 : 0}}
|
||||
bind:this={ref}
|
||||
on:focusout
|
||||
on:mouseenter
|
||||
on:mouseleave
|
||||
on:mousedown
|
||||
on:click
|
||||
on:keyup={handleKeyup}
|
||||
>
|
||||
{#if !multi && heading}
|
||||
<div class="heading">
|
||||
<h2>{heading}</h2>
|
||||
{#if helpURL}
|
||||
<HelpButton url={helpURL} desc={helpDesc}/>
|
||||
{:else if helpKey}
|
||||
<HelpButton key={helpKey} desc={helpDesc}/>
|
||||
{/if}
|
||||
<DefinedInWPConfig {defined}/>
|
||||
</div>
|
||||
{/if}
|
||||
<PanelContainer class={classes}>
|
||||
{#if multi && heading}
|
||||
<PanelRow header>
|
||||
{#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 -->
|
||||
<h3 on:click={headingClickHandler} class="toggler" class:toggleDisabled>{heading}</h3>
|
||||
{:else}
|
||||
<h3>{heading}</h3>
|
||||
{/if}
|
||||
<DefinedInWPConfig {defined}/>
|
||||
{#if refresh}
|
||||
<Button refresh {refreshing} title={refreshDesc} on:click={() => dispatch("refresh")}>{@html refreshText}</Button>
|
||||
{/if}
|
||||
{#if storageProvider}
|
||||
<div class="provider">
|
||||
<a href="/storage/provider" use:link class="link">
|
||||
<img src={storageProvider.link_icon} alt={storageProvider.icon_desc}>
|
||||
{storageProvider.provider_service_name}
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{#if helpURL}
|
||||
<HelpButton url={helpURL} desc={helpDesc}/>
|
||||
{:else if helpKey}
|
||||
<HelpButton key={helpKey} desc={helpDesc}/>
|
||||
{/if}
|
||||
</PanelRow>
|
||||
{/if}
|
||||
|
||||
<slot/>
|
||||
</PanelContainer>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.toggler:not(.toggleDisabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user