Skip to content

Commit f9128de

Browse files
authored
Merge pull request #18737 from craftcms/feature/edit-user-group
[6.x] User Groups create / edit
2 parents 893c651 + 2ef502a commit f9128de

39 files changed

Lines changed: 1339 additions & 1336 deletions

packages/craftcms-cp/scripts/generate-vue-wrappers.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,26 @@ function generateValueWrapper(component) {
230230
});
231231
232232
const model = defineModel<${component.modelType}>();
233+
234+
defineProps<{
235+
error?: null | string
236+
}>()
233237
</script>
234238
235239
<template>
236240
<${component.tagName}
237241
v-bind="$attrs"
238242
.modelValue="model"
239243
@model-value-changed="model = ($event.target as ${component.className})?.modelValue"
244+
:has-feedback-for="error ? 'error' : ''"
240245
>
241246
<slot></slot>
247+
248+
<div slot="feedback">
249+
<ul class="error-list" v-if="error">
250+
<li>{{ error }}</li>
251+
</ul>
252+
</div>
242253
</${component.tagName}>
243254
</template>
244255
`;

packages/craftcms-cp/src/components/checkbox/checkbox.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ export default class CraftCheckbox extends LionCheckbox {
88
css`
99
/* same as radio, potentially consolidate */
1010
:host {
11+
--_gap-x: var(--gap-x, --c-spacing-md);
1112
display: grid;
1213
align-items: center;
13-
gap: 0 var(--c-spacing-md);
14+
gap: 0 var(--_gap-x);
1415
grid-template-areas: 'input label' '. help-text';
1516
grid-template-columns: auto 1fr;
1617
grid-template-rows: repeat(2, auto);
@@ -36,6 +37,8 @@ export default class CraftCheckbox extends LionCheckbox {
3637
var(--c-form-control-border-color)
3738
);
3839
border-radius: var(--c-input-radius, var(--c-radius-sm));
40+
width: var(--c-size-control-2xs);
41+
height: var(--c-size-control-2xs);
3942
}
4043
4144
.choice-field__help-text {

packages/craftcms-cp/src/styles/shared/tokens.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@
137137
--c-size-icon-lg: calc(22rem / 16);
138138
--c-size-icon-xl: calc(30rem / 16);
139139

140+
--c-size-control-2xs: calc(14rem / 16);
140141
--c-size-control-xs: calc(16rem / 16);
141142
--c-size-control-sm: calc(24rem / 16);
142143
--c-size-control-md: calc(34rem / 16);

resources/js/components/ActionMenu.vue

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,18 @@
3030

3131
<template>
3232
<craft-action-menu>
33-
<craft-button
34-
type="button"
35-
slot="invoker"
36-
icon
37-
size="small"
38-
variant="inherit"
39-
appearance="plain"
40-
>
41-
<craft-icon :name="icon" :label="label"></craft-icon>
42-
</craft-button>
33+
<slot name="invoker" :label="label">
34+
<craft-button
35+
type="button"
36+
slot="invoker"
37+
icon
38+
size="small"
39+
variant="inherit"
40+
appearance="plain"
41+
>
42+
<craft-icon :name="icon" :label="label"></craft-icon>
43+
</craft-button>
44+
</slot>
4345

4446
<div slot="content" class="m-sm">
4547
<craft-action-item
@@ -48,18 +50,27 @@
4850
:key="`safe-${idx}`"
4951
:icon="action.icon"
5052
@click="action.onClick"
51-
>{{ action.label }}</craft-action-item
52-
>
53-
<hr class="m-0" />
54-
<craft-action-item
55-
v-for="(action, idx) in dangerousActions"
56-
:id="action.id"
57-
:key="`dangerous-${idx}`"
58-
:icon="action.icon"
59-
:variant="action.variant"
60-
@click="action.onClick"
61-
>{{ action.label }}</craft-action-item
62-
>
53+
>{{ action.label }}
54+
<craft-shortcut slot="suffix" class="ml-2" v-if="action.shortcut">{{
55+
action.shortcut
56+
}}</craft-shortcut>
57+
</craft-action-item>
58+
59+
<template v-if="dangerousActions.length">
60+
<hr class="m-0" />
61+
<craft-action-item
62+
v-for="(action, idx) in dangerousActions"
63+
:id="action.id"
64+
:key="`dangerous-${idx}`"
65+
:icon="action.icon"
66+
:variant="action.variant"
67+
@click="action.onClick"
68+
>{{ action.label }}
69+
<craft-shortcut slot="suffix" class="ml-2" v-if="action.shortcut">{{
70+
action.shortcut
71+
}}</craft-shortcut>
72+
</craft-action-item>
73+
</template>
6374
</div>
6475
</craft-action-menu>
6576
</template>

resources/js/components/Combobox.vue

Lines changed: 0 additions & 101 deletions
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<script setup lang="ts">
2+
import TransitionFade from '@/components/TransitionFade.vue';
3+
import {useFlash} from '@/composables/useFlash';
4+
5+
withDefaults(
6+
defineProps<{
7+
isActive?: boolean;
8+
}>(),
9+
{isActive: false}
10+
);
11+
12+
const {successFlash, errorFlash} = useFlash();
13+
</script>
14+
15+
<template>
16+
<TransitionFade>
17+
<template v-if="isActive && successFlash">
18+
<craft-callout
19+
variant="success"
20+
appearance="plain"
21+
icon="circle-check"
22+
inline
23+
class="p-0"
24+
>{{ successFlash }}</craft-callout
25+
>
26+
</template>
27+
<template v-if="isActive && errorFlash">
28+
<craft-callout
29+
variant="danger"
30+
appearance="plain"
31+
icon="triangle-exclamation"
32+
inline
33+
class="p-0"
34+
>
35+
{{ errorFlash }}
36+
</craft-callout>
37+
</template>
38+
</TransitionFade>
39+
</template>
40+
41+
<style scoped lang="scss"></style>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<script setup lang="ts">
2+
import {
3+
getNestedKeys,
4+
hasNested,
5+
type PermissionItem,
6+
} from '@/utils/permissions';
7+
import CraftCheckbox from '@craftcms/cp/vue/CraftCheckbox.vue';
8+
9+
const emit = defineEmits<{
10+
(e: 'update:modelValue', value: Array<string>): void;
11+
}>();
12+
const props = withDefaults(
13+
defineProps<{
14+
modelValue: Array<string>;
15+
permissions?: Record<string, PermissionItem>;
16+
disabled?: boolean;
17+
level?: number;
18+
}>(),
19+
{permissions: () => ({}), modelValue: () => [], disabled: false, level: 0}
20+
);
21+
22+
function toggleItem(key: string) {
23+
const lowerKey = key.toLowerCase();
24+
const index = props.modelValue.indexOf(lowerKey);
25+
if (index === -1) {
26+
emit('update:modelValue', [...props.modelValue, lowerKey]);
27+
} else {
28+
const keysToRemove = new Set([
29+
lowerKey,
30+
...getNestedKeys(props.permissions[key]),
31+
]);
32+
emit(
33+
'update:modelValue',
34+
props.modelValue.filter((v) => !keysToRemove.has(v))
35+
);
36+
}
37+
}
38+
</script>
39+
40+
<template>
41+
<ul
42+
class="group"
43+
v-for="(item, key) in permissions"
44+
:key="key"
45+
:style="{
46+
'--gap-x': `calc((${level} * 1lh) + var(--c-spacing-md))`,
47+
}"
48+
>
49+
<li>
50+
<CraftCheckbox
51+
:label="item.label"
52+
:model-value="modelValue.includes(key.toLowerCase())"
53+
:value="key"
54+
:disabled="disabled"
55+
@update:model-value="toggleItem(key)"
56+
:class="{
57+
'cp-checkbox-indentation': level! > 0,
58+
}"
59+
>
60+
<div v-if="item.info || item.warning" slot="help-text">
61+
<template v-if="item.info">
62+
{{ item.info }}
63+
</template>
64+
65+
<template v-if="item.warning">
66+
<div class="flex gap-1 items-center" data-color="warning">
67+
<craft-icon name="triangle-exclamation"></craft-icon>
68+
{{ item.warning }}
69+
</div>
70+
</template>
71+
</div>
72+
</CraftCheckbox>
73+
74+
<PermissionList
75+
v-if="hasNested(item)"
76+
:permissions="item.nested"
77+
:model-value="modelValue"
78+
:disabled="disabled || !modelValue.includes(item.key.toLowerCase())"
79+
@update:model-value="emit('update:modelValue', $event)"
80+
:level="level! + 1"
81+
/>
82+
</li>
83+
</ul>
84+
</template>
85+
86+
<style scoped lang="scss">
87+
.label {
88+
display: flex;
89+
}
90+
91+
.group {
92+
margin-block: var(--c-spacing-sm);
93+
}
94+
95+
.cp-checkbox-indentation {
96+
position: relative;
97+
}
98+
99+
.cp-checkbox-indentation::before {
100+
content: '';
101+
position: absolute;
102+
// Position the indicator halfway from the top of the checkbox
103+
inset-block-start: calc(1lh / 2);
104+
inset-inline-start: calc(
105+
var(--c-size-control-2xs) + (var(--c-spacing) * 2)
106+
);
107+
width: calc(var(--gap-x) - (var(--c-spacing) * 3.5));
108+
height: 1px;
109+
background-color: var(--c-color-neutral-border-quiet);
110+
}
111+
</style>

0 commit comments

Comments
 (0)