Skip to content

Commit 556ebb8

Browse files
committed
NEXT-33729 - Add staging mode
1 parent 97ae62c commit 556ebb8

File tree

35 files changed

+896
-28
lines changed

35 files changed

+896
-28
lines changed

.vscode/settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@
66
{"mode": "auto"}
77
],
88
"jest.rootPath": "src/Administration/Resources/app/administration",
9+
"php.problems.exclude": {
10+
"vendor-bin/": true,
11+
"tests/integration/Storefront/Theme/ThemeTest.php": [
12+
"PHP2408"
13+
]
14+
}
915
}

config-schema.json

+75
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@
101101
},
102102
"usage_data": {
103103
"$ref": "#/definitions/usage_data"
104+
},
105+
"staging": {
106+
"$ref": "#/definitions/staging"
104107
}
105108
},
106109
"title": "Shopware"
@@ -149,6 +152,78 @@
149152
},
150153
"title": "Usage data"
151154
},
155+
"staging": {
156+
"type": "object",
157+
"additionalProperties": false,
158+
"properties": {
159+
"mailing": {
160+
"type": "object",
161+
"additionalProperties": false,
162+
"properties": {
163+
"disable_delivery": {
164+
"type": "boolean",
165+
"default": true
166+
}
167+
}
168+
},
169+
"storefront": {
170+
"type": "object",
171+
"additionalProperties": false,
172+
"properties": {
173+
"show_banner": {
174+
"type": "boolean",
175+
"default": true
176+
}
177+
}
178+
},
179+
"administration": {
180+
"type": "object",
181+
"additionalProperties": false,
182+
"properties": {
183+
"show_banner": {
184+
"type": "boolean",
185+
"default": true
186+
}
187+
}
188+
},
189+
"sales_channel": {
190+
"type": "object",
191+
"additionalProperties": false,
192+
"properties": {
193+
"domain_rewrite": {
194+
"type": "array",
195+
"items": {
196+
"type": "object",
197+
"additionalProperties": false,
198+
"properties": {
199+
"match": {
200+
"type": "string"
201+
},
202+
"type": {
203+
"type": "string",
204+
"enum": ["equal", "regex", "prefix"]
205+
},
206+
"replace": {
207+
"type": "string"
208+
}
209+
}
210+
}
211+
}
212+
}
213+
},
214+
"elasticsearch": {
215+
"type": "object",
216+
"additionalProperties": false,
217+
"properties": {
218+
"check_for_existence": {
219+
"type": "boolean",
220+
"default": true
221+
}
222+
}
223+
}
224+
},
225+
"title": "Staging"
226+
},
152227
"twig": {
153228
"type": "object",
154229
"additionalProperties": false,

src/Administration/Resources/app/administration/src/app/component/structure/sw-desktop/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,17 @@ Component.register('sw-desktop', {
2525
desktopClasses() {
2626
return {
2727
'sw-desktop--no-nav': this.noNavigation,
28+
'sw-desktop--staging': this.isStaging,
2829
};
2930
},
3031

3132
currentUser() {
3233
return Shopware.State.get('session').currentUser;
3334
},
35+
36+
isStaging() {
37+
return Shopware.State.get('context').app.config.settings.enableStagingMode === true;
38+
},
3439
},
3540

3641
watch: {

src/Administration/Resources/app/administration/src/app/component/structure/sw-desktop/sw-desktop.html.twig

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
class="sw-desktop"
55
:class="desktopClasses"
66
>
7+
<div
8+
v-if="isStaging"
9+
class="sw-staging-bar">
10+
{{ $tc('global.sw-desktop.stagingBarText') }}
11+
</div>
712

813
<!-- eslint-disable-next-line sw-deprecation-rules/no-twigjs-blocks -->
914
{% block sw_desktop_sidebar %}

src/Administration/Resources/app/administration/src/app/component/structure/sw-desktop/sw-desktop.scss

+15
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,26 @@
1010
grid-template-columns: 1fr;
1111
}
1212

13+
&.sw-desktop--staging {
14+
grid-template-rows: 50px auto;
15+
}
16+
1317
@media screen and (max-width: 500px) {
1418
display: block;
1519

1620
.sw-desktop__content {
1721
height: 100%;
1822
}
1923
}
24+
25+
.sw-staging-bar {
26+
grid-column: 1 / 3;
27+
display: flex;
28+
justify-content: center;
29+
background: rgb(61, 68, 77);
30+
color: white;
31+
font-weight: bold;
32+
padding: 1rem;
33+
position: sticky;
34+
}
2035
}

src/Administration/Resources/app/administration/src/app/component/structure/sw-desktop/sw-desktop.spec.js

+16
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,20 @@ describe('src/app/component/structure/sw-desktop', () => {
212212

213213
expect(urlDiffSpy).not.toHaveBeenCalled();
214214
});
215+
216+
it('should show the staging bar, when enabled', async () => {
217+
Shopware.State.get('context').app.config.settings.enableStagingMode = true;
218+
219+
const wrapper = await createWrapper();
220+
expect(wrapper.vm).toBeTruthy();
221+
expect(wrapper.find('.sw-staging-bar').exists()).toBeTruthy();
222+
});
223+
224+
it('should not show the staging bar, when disabled', async () => {
225+
Shopware.State.get('context').app.config.settings.enableStagingMode = false;
226+
227+
const wrapper = await createWrapper();
228+
expect(wrapper.vm).toBeTruthy();
229+
expect(wrapper.find('.sw-staging-bar').exists()).toBeFalsy();
230+
});
215231
});

src/Administration/Resources/app/administration/src/app/snippet/de-DE.json

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
"noMessage": "Eine Nachricht wurde nicht definiert",
5858
"notificationLoadingDataErrorMessage": "Fehler beim Laden der Daten"
5959
},
60+
"sw-desktop": {
61+
"stagingBarText": "The Shop befindet sich im Staging mode."
62+
},
6063
"notification-center": {
6164
"title": "Mitteilungen",
6265
"emptyText": "Nicht viel los hier.",

src/Administration/Resources/app/administration/src/app/snippet/en-GB.json

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
"noMessage": "Message is not defined",
5858
"notificationLoadingDataErrorMessage": "Error loading data"
5959
},
60+
"sw-desktop": {
61+
"stagingBarText": "The Shop is in staging mode."
62+
},
6063
"notification-center": {
6164
"title": "Notifications",
6265
"emptyText": "Nothing going on lately.",

src/Core/Content/Mail/Service/MailSender.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#[Package('system-settings')]
1414
class MailSender extends AbstractMailSender
1515
{
16+
public const DISABLE_MAIL_DELIVERY = 'core.mailerSettings.disableDelivery';
17+
1618
/**
1719
* @internal
1820
*/
@@ -34,7 +36,7 @@ public function send(Email $email, ?Envelope $envelope = null): void
3436
{
3537
$failedRecipients = [];
3638

37-
$disabled = $this->configService->get('core.mailerSettings.disableDelivery');
39+
$disabled = $this->configService->get(self::DISABLE_MAIL_DELIVERY);
3840
if ($disabled) {
3941
return;
4042
}

src/Core/Framework/Api/Controller/InfoController.php

+11-16
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
use Shopware\Core\Framework\Log\Package;
1717
use Shopware\Core\Framework\Plugin;
1818
use Shopware\Core\Kernel;
19+
use Shopware\Core\Maintenance\Staging\Event\SetupStagingEvent;
1920
use Shopware\Core\Maintenance\System\Service\AppUrlVerifier;
2021
use Shopware\Core\PlatformRequest;
22+
use Shopware\Core\System\SystemConfig\SystemConfigService;
2123
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
2224
use Symfony\Component\Asset\PackageInterface;
2325
use Symfony\Component\Asset\Packages;
@@ -26,15 +28,14 @@
2628
use Symfony\Component\HttpFoundation\Request;
2729
use Symfony\Component\HttpFoundation\Response;
2830
use Symfony\Component\Routing\Attribute\Route;
31+
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
2932
use Symfony\Component\Routing\RouterInterface;
3033

3134
#[Route(defaults: ['_routeScope' => ['api']])]
3235
#[Package('core')]
3336
class InfoController extends AbstractController
3437
{
3538
/**
36-
* @param array{administration?: string} $cspTemplates
37-
*
3839
* @internal
3940
*/
4041
public function __construct(
@@ -47,9 +48,8 @@ public function __construct(
4748
private readonly Connection $connection,
4849
private readonly AppUrlVerifier $appUrlVerifier,
4950
private readonly RouterInterface $router,
50-
private readonly ?FlowActionCollector $flowActionCollector = null,
51-
private readonly bool $enableUrlFeature = true,
52-
private readonly array $cspTemplates = [],
51+
private readonly FlowActionCollector $flowActionCollector,
52+
private readonly SystemConfigService $systemConfigService
5353
) {
5454
}
5555

@@ -128,7 +128,7 @@ public function infoHtml(Request $request): Response
128128
]
129129
);
130130

131-
$cspTemplate = $this->cspTemplates['administration'] ?? '';
131+
$cspTemplate = $this->params->get('shopware.security.csp_templates')['administration'] ?? '';
132132
$cspTemplate = trim($cspTemplate);
133133
if ($cspTemplate !== '') {
134134
$csp = str_replace('%nonce%', $nonce, $cspTemplate);
@@ -153,7 +153,7 @@ public function stoplightIoInfoHtml(Request $request): Response
153153
]
154154
);
155155

156-
$cspTemplate = $this->cspTemplates['administration'] ?? '';
156+
$cspTemplate = $this->params->get('shopware.security.csp_templates')['administration'] ?? '';
157157
$cspTemplate = trim($cspTemplate);
158158
if ($cspTemplate !== '') {
159159
$csp = str_replace('%nonce%', $nonce, $cspTemplate);
@@ -178,11 +178,12 @@ public function config(Context $context, Request $request): JsonResponse
178178
],
179179
'bundles' => $this->getBundles(),
180180
'settings' => [
181-
'enableUrlFeature' => $this->enableUrlFeature,
181+
'enableUrlFeature' => $this->params->get('shopware.media.enable_url_upload_feature'),
182182
'appUrlReachable' => $this->appUrlVerifier->isAppUrlReachable($request),
183183
'appsRequireAppUrl' => $this->appUrlVerifier->hasAppsThatNeedAppUrl(),
184184
'private_allowed_extensions' => $this->params->get('shopware.filesystem.private_allowed_extensions'),
185185
'enableHtmlSanitizer' => $this->params->get('shopware.html_sanitizer.enabled'),
186+
'enableStagingMode' => $this->params->get('shopware.staging.administration.show_banner') && $this->systemConfigService->getBool(SetupStagingEvent::CONFIG_FLAG),
186187
],
187188
]);
188189
}
@@ -199,13 +200,7 @@ public function infoShopwareVersion(): JsonResponse
199200
#[Route(path: '/api/_info/flow-actions.json', name: 'api.info.actions', methods: ['GET'])]
200201
public function flowActions(Context $context): JsonResponse
201202
{
202-
if (!$this->flowActionCollector) {
203-
return $this->json([]);
204-
}
205-
206-
$events = $this->flowActionCollector->collect($context);
207-
208-
return new JsonResponse($events);
203+
return new JsonResponse($this->flowActionCollector->collect($context));
209204
}
210205

211206
/**
@@ -323,7 +318,7 @@ private function getBaseUrl(Bundle $bundle, PackageInterface $package, string $b
323318
[
324319
'pluginName' => \mb_strtolower($bundle->getName()),
325320
],
326-
RouterInterface::ABSOLUTE_URL
321+
UrlGeneratorInterface::ABSOLUTE_URL
327322
);
328323
} catch (\Exception $e) {
329324
return null;

src/Core/Framework/DependencyInjection/Configuration.php

+46
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function getConfigTreeBuilder(): TreeBuilder
4444
->append($this->createStockSection())
4545
->append($this->createUsageDataSection())
4646
->append($this->createFeatureToggleNode())
47+
->append($this->createStagingNode())
4748
->end();
4849

4950
return $treeBuilder;
@@ -760,6 +761,51 @@ private function createFeatureToggleNode(): ArrayNodeDefinition
760761
return $rootNode;
761762
}
762763

764+
private function createStagingNode(): ArrayNodeDefinition
765+
{
766+
$treeBuilder = new TreeBuilder('staging');
767+
768+
$rootNode = $treeBuilder->getRootNode();
769+
$rootNode
770+
->children()
771+
->arrayNode('mailing')
772+
->children()
773+
->booleanNode('disable_delivery')->defaultTrue()->end()
774+
->end()
775+
->end()
776+
->arrayNode('storefront')
777+
->children()
778+
->booleanNode('show_banner')->defaultTrue()->end()
779+
->end()
780+
->end()
781+
->arrayNode('administration')
782+
->children()
783+
->booleanNode('show_banner')->defaultTrue()->end()
784+
->end()
785+
->end()
786+
->arrayNode('sales_channel')
787+
->children()
788+
->arrayNode('domain_rewrite')
789+
->arrayPrototype()
790+
->children()
791+
->scalarNode('match')->end()
792+
->scalarNode('type')->defaultValue('equal')->end()
793+
->scalarNode('replace')->end()
794+
->end()
795+
->end()
796+
->end()
797+
->end()
798+
->end()
799+
->arrayNode('elasticsearch')
800+
->children()
801+
->booleanNode('check_for_existence')->defaultTrue()->end()
802+
->end()
803+
->end()
804+
->end();
805+
806+
return $rootNode;
807+
}
808+
763809
private function createHttpCacheSection(): ArrayNodeDefinition
764810
{
765811
$treeBuilder = new TreeBuilder('http_cache');

src/Core/Framework/DependencyInjection/api.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@
167167
<argument type="service" id="Doctrine\DBAL\Connection"/>
168168
<argument type="service" id="Shopware\Core\Maintenance\System\Service\AppUrlVerifier"/>
169169
<argument type="service" id="router"/>
170-
<argument type="service" id="Shopware\Core\Content\Flow\Api\FlowActionCollector" on-invalid="null"/>
171-
<argument>%shopware.media.enable_url_upload_feature%</argument>
172-
<argument>%shopware.security.csp_templates%</argument>
170+
<argument type="service" id="Shopware\Core\Content\Flow\Api\FlowActionCollector"/>
171+
<argument type="service" id="Shopware\Core\System\SystemConfig\SystemConfigService"/>
172+
173173
<call method="setContainer">
174174
<argument type="service" id="service_container"/>
175175
</call>

0 commit comments

Comments
 (0)