Skip to content

Commit

Permalink
FEATURE: Set basic visibility on workspace creation
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebobo committed Dec 17, 2024
1 parent b22d0c7 commit ccdd46c
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 95 deletions.
15 changes: 15 additions & 0 deletions Neos.Neos/Classes/Domain/Model/WorkspaceRoleAssignments.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,21 @@ public static function createForSharedWorkspace(UserId $userId): self
);
}

/**
* Default role assignment to be specified at creation via {@see WorkspaceService::createSharedWorkspace()}
*
* The specified user is manager
*/
public static function createForPrivateWorkspace(UserId $userId): self
{
return new self(
WorkspaceRoleAssignment::createForUser(
$userId,
WorkspaceRole::MANAGER,
)
);
}

public function isEmpty(): bool
{
return $this->assignments === [];
Expand Down
10 changes: 7 additions & 3 deletions Neos.Workspace.Ui/Classes/Controller/WorkspaceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
use Neos\Neos\Domain\Model\User;
use Neos\Neos\Domain\Model\WorkspaceClassification;
use Neos\Neos\Domain\Model\WorkspaceDescription;
use Neos\Neos\Domain\Model\WorkspaceRole;
use Neos\Neos\Domain\Model\WorkspaceRoleAssignment;
use Neos\Neos\Domain\Model\WorkspaceRoleAssignments;
use Neos\Neos\Domain\Model\WorkspaceTitle;
use Neos\Neos\Domain\NodeLabel\NodeLabelGeneratorInterface;
Expand Down Expand Up @@ -234,6 +236,7 @@ public function createAction(
WorkspaceTitle $title,
WorkspaceName $baseWorkspace,
WorkspaceDescription $description,
string $visibility = 'shared',
): void {
$currentUser = $this->userService->getCurrentUser();
if ($currentUser === null) {
Expand All @@ -244,15 +247,16 @@ public function createAction(
$workspaceName = $this->workspaceService->getUniqueWorkspaceName($contentRepositoryId, $title->value);

try {
$assignments = $visibility === 'shared' ?
WorkspaceRoleAssignments::createForSharedWorkspace($currentUser->getId()) :
WorkspaceRoleAssignments::createForPrivateWorkspace($currentUser->getId());
$this->workspaceService->createSharedWorkspace(
$contentRepositoryId,
$workspaceName,
$title,
$description,
$baseWorkspace,
WorkspaceRoleAssignments::createForSharedWorkspace(
$currentUser->getId()
)
$assignments
);
} catch (WorkspaceAlreadyExists $exception) {
$this->addFlashMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
# Delete confirmation modal with empty POST response
#
Neos.Workspace.Ui.WorkspaceController.delete = Neos.Fusion:Component {
/// string
workspaceName = ${workspaceName}
/// string
workspaceTitle = ${workspaceTitle}

renderer = Neos.Fusion:Match {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,97 +1,16 @@
Neos.Workspace.Ui.WorkspaceController.new = Neos.Fusion:Component {
/// array<string>
baseWorkspaceOptions = ${baseWorkspaceOptions}
workspace = ${workspace}
i18n = ${I18n.id('').source('Main').package('Neos.Workspace.Ui')}
popoverId = 'create-workspace-popover'

prototype(Neos.Fusion.Form:LabelRenderer) {
translationPackage = 'Neos.Workspace.Ui'
translationSource = 'Main'
renderer = Neos.Fusion:Match {
@subject = ${request.httpRequest.method}
# Render the create modal
@default = afx`
<Neos.Workspace.Ui:Component.Modal.Create
baseWorkspaceOptions={props.baseWorkspaceOptions}
/>
`
# Empty template for the delete response as the payload is contained in the HTTP headers
POST = ''
}

prototype(Neos.Fusion.Form:Neos.BackendModule.FieldContainer) {
translation.label {
package = 'Neos.Workspace.Ui'
source = 'Main'
}
}

renderer = afx`
<div popover id={props.popoverId}>
<header>
<button
type="button"
class="neos-close neos-button"
popovertarget={props.popoverId}
popovertargetaction="close"
>
<Neos.Workspace.Ui:Component.Icon icon="times"/>
</button>
<div class="neos-header">
{props.i18n.id('workspaces.createNewWorkspace')}
</div>
</header>
<Neos.Fusion.Form:Form
form.target.action="create"
form.target.format="htmx"
attributes.hx-post={form.getTarget()}
attributes.hx-disabled-elt="find button"
attributes.hx-on--after-request={'document.getElementById("' + props.popoverId + '").hidePopover()'}
>
<section>
<fieldset>
<!-- todo adjust labels to be not that nested -->
<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
field.name="title"
label="workspaces.workspace.title"
class="neos-control-group"
>
<Neos.Fusion.Form:Textfield
attributes.required
attributes.pattern="/^[\p{L}\p{P}\d \.]{1,200}$/u"
attributes.autofocus
/>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>

<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
field.name="description"
label="workspaces.workspace.description"
class="neos-control-group"
>
<Neos.Fusion.Form:Textfield
attributes.pattern="/^[\p{L}\p{P}\d \.]{0,500}$/u"
/>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>

<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
field.name="baseWorkspace"
field.value="live"
label="workspaces.workspace.baseWorkspace"
class="neos-control-group"
>
<Neos.Fusion.Form:Select>
<Neos.Fusion:Loop items={props.baseWorkspaceOptions} itemName="workspaceTitle" itemKey="workspaceName">
<Neos.Fusion.Form:Select.Option
option.value={workspaceName}>{workspaceTitle}</Neos.Fusion.Form:Select.Option>
</Neos.Fusion:Loop>
</Neos.Fusion.Form:Select>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>
</fieldset>
</section>
<footer>
<button
type="button"
class="neos-button"
popovertarget={props.popoverId}
popovertargetaction="close"
>
{props.i18n.id('cancel')}
</button>
<Neos.Fusion.Form:Button attributes.class="neos-button neos-button-primary">
{props.i18n.id('workspaces.createWorkspace')}
</Neos.Fusion.Form:Button>
</footer>
</Neos.Fusion.Form:Form>
</div>
`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
prototype(Neos.Workspace.Ui:Component.Modal.Create) < prototype(Neos.Fusion:Component) {
/// array<string>
baseWorkspaceOptions = null

@private {
i18n = ${I18n.id('').source('Main').package('Neos.Workspace.Ui')}
popoverId = 'create-workspace-popover'
}

prototype(Neos.Fusion.Form:LabelRenderer) {
translationPackage = 'Neos.Workspace.Ui'
translationSource = 'Main'
}

prototype(Neos.Fusion.Form:Neos.BackendModule.FieldContainer) {
translation.label {
package = 'Neos.Workspace.Ui'
source = 'Main'
}
}

renderer = afx`
<div popover id={private.popoverId}>
<header>
<button
type="button"
class="neos-close neos-button"
popovertarget={private.popoverId}
popovertargetaction="close"
>
<Neos.Workspace.Ui:Component.Icon icon="times"/>
</button>
<div class="neos-header">
{private.i18n.id('workspaces.createNewWorkspace')}
</div>
</header>
<Neos.Fusion.Form:Form
form.target.action="create"
form.target.format="htmx"
attributes.hx-post={form.getTarget()}
attributes.hx-disabled-elt="find button"
attributes.hx-on--after-request={'document.getElementById("' + private.popoverId + '").hidePopover()'}
>
<section>
<fieldset>
<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
field.name="title"
label="workspaces.workspace.title"
class="neos-control-group"
>
<Neos.Fusion.Form:Textfield
attributes.required
attributes.pattern="/^[\p{L}\p{P}\d \.]{1,200}$/u"
attributes.autofocus
/>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>

<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
field.name="description"
label="workspaces.workspace.description"
class="neos-control-group"
>
<Neos.Fusion.Form:Textfield
attributes.pattern="/^[\p{L}\p{P}\d \.]{0,500}$/u"
/>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>

<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
field.name="baseWorkspace"
field.value="live"
label="workspaces.workspace.baseWorkspace"
class="neos-control-group"
>
<Neos.Fusion.Form:Select>
<Neos.Fusion:Loop items={props.baseWorkspaceOptions} itemName="workspaceTitle" itemKey="workspaceName">
<Neos.Fusion.Form:Select.Option
option.value={workspaceName}>{workspaceTitle}</Neos.Fusion.Form:Select.Option>
</Neos.Fusion:Loop>
</Neos.Fusion.Form:Select>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>

<Neos.Fusion.Form:Neos.BackendModule.FieldContainer
label="workspaces.workspace.visibility"
class="neos-control-group"
>
<Neos.Fusion.Form:Radio
renderer.checked
field.name="visibility"
field.value="shared"
>
{private.i18n.id('workspaces.workspace.visibility.internal')}
</Neos.Fusion.Form:Radio>
<p>
{private.i18n.id('workspaces.workspace.visibility.internal.help')}
</p>
<br/>
<Neos.Fusion.Form:Radio
field.name="visibility"
field.value="private"
>
{private.i18n.id('workspaces.workspace.visibility.private')}
</Neos.Fusion.Form:Radio>
<p>
{private.i18n.id('workspaces.workspace.visibility.private.help')}
</p>
</Neos.Fusion.Form:Neos.BackendModule.FieldContainer>
</fieldset>
</section>
<footer>
<button
type="button"
class="neos-button"
popovertarget={private.popoverId}
popovertargetaction="close"
>
{private.i18n.id('cancel')}
</button>
<Neos.Fusion.Form:Button attributes.class="neos-button neos-button-primary">
{private.i18n.id('workspaces.createWorkspace')}
</Neos.Fusion.Form:Button>
</footer>
</Neos.Fusion.Form:Form>
</div>
`
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
prototype(Neos.Workspace.Ui:Component.Modal.Delete) < prototype(Neos.Fusion:Component) {
/// string
workspaceName = null
/// string
workspaceTitle = null

@private {
Expand Down

0 comments on commit ccdd46c

Please sign in to comment.