@lightdash/common 0.2572.2 → 0.2573.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/authorization/space/spaceAccessResolver.d.ts +2 -3
- package/dist/cjs/authorization/space/spaceAccessResolver.d.ts.map +1 -1
- package/dist/cjs/authorization/space/spaceAccessResolver.js +14 -78
- package/dist/cjs/authorization/space/spaceAccessResolver.js.map +1 -1
- package/dist/cjs/authorization/space/spaceAccessResolver.test.js +18 -529
- package/dist/cjs/authorization/space/spaceAccessResolver.test.js.map +1 -1
- package/dist/cjs/compiler/exploreCompiler.d.ts.map +1 -1
- package/dist/cjs/compiler/exploreCompiler.js +5 -3
- package/dist/cjs/compiler/exploreCompiler.js.map +1 -1
- package/dist/cjs/compiler/filtersCompiler.d.ts.map +1 -1
- package/dist/cjs/compiler/filtersCompiler.js +1 -0
- package/dist/cjs/compiler/filtersCompiler.js.map +1 -1
- package/dist/cjs/dbt/schemas/lightdashMetadata.json +1 -0
- package/dist/cjs/ee/AiAgent/schemas/customMetrics.d.ts +148 -148
- package/dist/cjs/ee/AiAgent/schemas/filters/index.d.ts +180 -180
- package/dist/cjs/ee/AiAgent/schemas/filters/numberFilters.d.ts +12 -12
- package/dist/cjs/ee/AiAgent/schemas/filters/numberFilters.d.ts.map +1 -1
- package/dist/cjs/ee/AiAgent/schemas/filters/numberFilters.js +1 -0
- package/dist/cjs/ee/AiAgent/schemas/filters/numberFilters.js.map +1 -1
- package/dist/cjs/ee/AiAgent/schemas/tools/toolDashboardArgs.d.ts +1608 -1608
- package/dist/cjs/ee/AiAgent/schemas/tools/toolDashboardV2Args.d.ts +440 -440
- package/dist/cjs/ee/AiAgent/schemas/tools/toolProposeChangeArgs.d.ts +60 -60
- package/dist/cjs/ee/AiAgent/schemas/tools/toolRunMetricQueryArgs.d.ts +256 -256
- package/dist/cjs/ee/AiAgent/schemas/tools/toolRunQueryArgs.d.ts +256 -256
- package/dist/cjs/ee/AiAgent/schemas/tools/toolSearchFieldValuesArgs.d.ts +180 -180
- package/dist/cjs/ee/AiAgent/schemas/tools/toolTableVizArgs.d.ts +320 -320
- package/dist/cjs/ee/AiAgent/schemas/tools/toolTimeSeriesArgs.d.ts +320 -320
- package/dist/cjs/ee/AiAgent/schemas/tools/toolVerticalBarArgs.d.ts +320 -320
- package/dist/cjs/preAggregates/additivity.d.ts.map +1 -1
- package/dist/cjs/preAggregates/additivity.js +1 -0
- package/dist/cjs/preAggregates/additivity.js.map +1 -1
- package/dist/cjs/preAggregates/metricRepresentation.d.ts.map +1 -1
- package/dist/cjs/preAggregates/metricRepresentation.js +1 -0
- package/dist/cjs/preAggregates/metricRepresentation.js.map +1 -1
- package/dist/cjs/schemas/json/chart-as-code-1.0.json +443 -114
- package/dist/cjs/types/catalog.d.ts.map +1 -1
- package/dist/cjs/types/catalog.js +1 -0
- package/dist/cjs/types/catalog.js.map +1 -1
- package/dist/cjs/types/featureFlags.d.ts +0 -6
- package/dist/cjs/types/featureFlags.d.ts.map +1 -1
- package/dist/cjs/types/featureFlags.js +0 -6
- package/dist/cjs/types/featureFlags.js.map +1 -1
- package/dist/cjs/types/field.d.ts +1 -0
- package/dist/cjs/types/field.d.ts.map +1 -1
- package/dist/cjs/types/field.js +3 -0
- package/dist/cjs/types/field.js.map +1 -1
- package/dist/cjs/types/results.d.ts.map +1 -1
- package/dist/cjs/types/results.js +1 -0
- package/dist/cjs/types/results.js.map +1 -1
- package/dist/cjs/types/space.d.ts +0 -7
- package/dist/cjs/types/space.d.ts.map +1 -1
- package/dist/cjs/types/space.js.map +1 -1
- package/dist/cjs/utils/filters.d.ts.map +1 -1
- package/dist/cjs/utils/filters.js +1 -0
- package/dist/cjs/utils/filters.js.map +1 -1
- package/dist/cjs/utils/item.d.ts.map +1 -1
- package/dist/cjs/utils/item.js +1 -0
- package/dist/cjs/utils/item.js.map +1 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/authorization/space/spaceAccessResolver.d.ts +2 -3
- package/dist/esm/authorization/space/spaceAccessResolver.d.ts.map +1 -1
- package/dist/esm/authorization/space/spaceAccessResolver.js +6 -69
- package/dist/esm/authorization/space/spaceAccessResolver.js.map +1 -1
- package/dist/esm/authorization/space/spaceAccessResolver.test.js +19 -530
- package/dist/esm/authorization/space/spaceAccessResolver.test.js.map +1 -1
- package/dist/esm/compiler/exploreCompiler.d.ts.map +1 -1
- package/dist/esm/compiler/exploreCompiler.js +5 -3
- package/dist/esm/compiler/exploreCompiler.js.map +1 -1
- package/dist/esm/compiler/filtersCompiler.d.ts.map +1 -1
- package/dist/esm/compiler/filtersCompiler.js +1 -0
- package/dist/esm/compiler/filtersCompiler.js.map +1 -1
- package/dist/esm/dbt/schemas/lightdashMetadata.json +1 -0
- package/dist/esm/ee/AiAgent/schemas/customMetrics.d.ts +148 -148
- package/dist/esm/ee/AiAgent/schemas/filters/index.d.ts +180 -180
- package/dist/esm/ee/AiAgent/schemas/filters/numberFilters.d.ts +12 -12
- package/dist/esm/ee/AiAgent/schemas/filters/numberFilters.d.ts.map +1 -1
- package/dist/esm/ee/AiAgent/schemas/filters/numberFilters.js +1 -0
- package/dist/esm/ee/AiAgent/schemas/filters/numberFilters.js.map +1 -1
- package/dist/esm/ee/AiAgent/schemas/tools/toolDashboardArgs.d.ts +1608 -1608
- package/dist/esm/ee/AiAgent/schemas/tools/toolDashboardV2Args.d.ts +440 -440
- package/dist/esm/ee/AiAgent/schemas/tools/toolProposeChangeArgs.d.ts +60 -60
- package/dist/esm/ee/AiAgent/schemas/tools/toolRunMetricQueryArgs.d.ts +256 -256
- package/dist/esm/ee/AiAgent/schemas/tools/toolRunQueryArgs.d.ts +256 -256
- package/dist/esm/ee/AiAgent/schemas/tools/toolSearchFieldValuesArgs.d.ts +180 -180
- package/dist/esm/ee/AiAgent/schemas/tools/toolTableVizArgs.d.ts +320 -320
- package/dist/esm/ee/AiAgent/schemas/tools/toolTimeSeriesArgs.d.ts +320 -320
- package/dist/esm/ee/AiAgent/schemas/tools/toolVerticalBarArgs.d.ts +320 -320
- package/dist/esm/preAggregates/additivity.d.ts.map +1 -1
- package/dist/esm/preAggregates/additivity.js +1 -0
- package/dist/esm/preAggregates/additivity.js.map +1 -1
- package/dist/esm/preAggregates/metricRepresentation.d.ts.map +1 -1
- package/dist/esm/preAggregates/metricRepresentation.js +1 -0
- package/dist/esm/preAggregates/metricRepresentation.js.map +1 -1
- package/dist/esm/schemas/json/chart-as-code-1.0.json +443 -114
- package/dist/esm/types/catalog.d.ts.map +1 -1
- package/dist/esm/types/catalog.js +1 -0
- package/dist/esm/types/catalog.js.map +1 -1
- package/dist/esm/types/featureFlags.d.ts +0 -6
- package/dist/esm/types/featureFlags.d.ts.map +1 -1
- package/dist/esm/types/featureFlags.js +0 -6
- package/dist/esm/types/featureFlags.js.map +1 -1
- package/dist/esm/types/field.d.ts +1 -0
- package/dist/esm/types/field.d.ts.map +1 -1
- package/dist/esm/types/field.js +3 -0
- package/dist/esm/types/field.js.map +1 -1
- package/dist/esm/types/results.d.ts.map +1 -1
- package/dist/esm/types/results.js +1 -0
- package/dist/esm/types/results.js.map +1 -1
- package/dist/esm/types/space.d.ts +0 -7
- package/dist/esm/types/space.d.ts.map +1 -1
- package/dist/esm/types/space.js.map +1 -1
- package/dist/esm/utils/filters.d.ts.map +1 -1
- package/dist/esm/utils/filters.js +1 -0
- package/dist/esm/utils/filters.js.map +1 -1
- package/dist/esm/utils/item.d.ts.map +1 -1
- package/dist/esm/utils/item.js +1 -0
- package/dist/esm/utils/item.js.map +1 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/authorization/space/spaceAccessResolver.d.ts +2 -3
- package/dist/types/authorization/space/spaceAccessResolver.d.ts.map +1 -1
- package/dist/types/authorization/space/spaceAccessResolver.js +6 -69
- package/dist/types/authorization/space/spaceAccessResolver.js.map +1 -1
- package/dist/types/authorization/space/spaceAccessResolver.test.js +19 -530
- package/dist/types/authorization/space/spaceAccessResolver.test.js.map +1 -1
- package/dist/types/compiler/exploreCompiler.d.ts.map +1 -1
- package/dist/types/compiler/exploreCompiler.js +5 -3
- package/dist/types/compiler/exploreCompiler.js.map +1 -1
- package/dist/types/compiler/filtersCompiler.d.ts.map +1 -1
- package/dist/types/compiler/filtersCompiler.js +1 -0
- package/dist/types/compiler/filtersCompiler.js.map +1 -1
- package/dist/types/dbt/schemas/lightdashMetadata.json +1 -0
- package/dist/types/ee/AiAgent/schemas/customMetrics.d.ts +148 -148
- package/dist/types/ee/AiAgent/schemas/filters/index.d.ts +180 -180
- package/dist/types/ee/AiAgent/schemas/filters/numberFilters.d.ts +12 -12
- package/dist/types/ee/AiAgent/schemas/filters/numberFilters.d.ts.map +1 -1
- package/dist/types/ee/AiAgent/schemas/filters/numberFilters.js +1 -0
- package/dist/types/ee/AiAgent/schemas/filters/numberFilters.js.map +1 -1
- package/dist/types/ee/AiAgent/schemas/tools/toolDashboardArgs.d.ts +1608 -1608
- package/dist/types/ee/AiAgent/schemas/tools/toolDashboardV2Args.d.ts +440 -440
- package/dist/types/ee/AiAgent/schemas/tools/toolProposeChangeArgs.d.ts +60 -60
- package/dist/types/ee/AiAgent/schemas/tools/toolRunMetricQueryArgs.d.ts +256 -256
- package/dist/types/ee/AiAgent/schemas/tools/toolRunQueryArgs.d.ts +256 -256
- package/dist/types/ee/AiAgent/schemas/tools/toolSearchFieldValuesArgs.d.ts +180 -180
- package/dist/types/ee/AiAgent/schemas/tools/toolTableVizArgs.d.ts +320 -320
- package/dist/types/ee/AiAgent/schemas/tools/toolTimeSeriesArgs.d.ts +320 -320
- package/dist/types/ee/AiAgent/schemas/tools/toolVerticalBarArgs.d.ts +320 -320
- package/dist/types/preAggregates/additivity.d.ts.map +1 -1
- package/dist/types/preAggregates/additivity.js +1 -0
- package/dist/types/preAggregates/additivity.js.map +1 -1
- package/dist/types/preAggregates/metricRepresentation.d.ts.map +1 -1
- package/dist/types/preAggregates/metricRepresentation.js +1 -0
- package/dist/types/preAggregates/metricRepresentation.js.map +1 -1
- package/dist/types/schemas/json/chart-as-code-1.0.json +443 -114
- package/dist/types/types/catalog.d.ts.map +1 -1
- package/dist/types/types/catalog.js +1 -0
- package/dist/types/types/catalog.js.map +1 -1
- package/dist/types/types/featureFlags.d.ts +0 -6
- package/dist/types/types/featureFlags.d.ts.map +1 -1
- package/dist/types/types/featureFlags.js +0 -6
- package/dist/types/types/featureFlags.js.map +1 -1
- package/dist/types/types/field.d.ts +1 -0
- package/dist/types/types/field.d.ts.map +1 -1
- package/dist/types/types/field.js +3 -0
- package/dist/types/types/field.js.map +1 -1
- package/dist/types/types/results.d.ts.map +1 -1
- package/dist/types/types/results.js +1 -0
- package/dist/types/types/results.js.map +1 -1
- package/dist/types/types/space.d.ts +0 -7
- package/dist/types/types/space.d.ts.map +1 -1
- package/dist/types/types/space.js.map +1 -1
- package/dist/types/utils/filters.d.ts.map +1 -1
- package/dist/types/utils/filters.js +1 -0
- package/dist/types/utils/filters.js.map +1 -1
- package/dist/types/utils/item.d.ts.map +1 -1
- package/dist/types/utils/item.js +1 -0
- package/dist/types/utils/item.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,519 +1,8 @@
|
|
|
1
1
|
import { OrganizationMemberRole } from '../../types/organizationMemberProfile';
|
|
2
2
|
import { ProjectMemberRole } from '../../types/projectMemberRole';
|
|
3
3
|
import { DirectSpaceAccessOrigin, ProjectSpaceAccessOrigin, SpaceMemberRole, } from '../../types/space';
|
|
4
|
-
import { resolveSpaceAccess
|
|
5
|
-
const makeInput = (overrides = {}) => ({
|
|
6
|
-
spaceUuid: 'space-1',
|
|
7
|
-
inheritsFromOrgOrProject: true,
|
|
8
|
-
directAccess: [],
|
|
9
|
-
projectAccess: [],
|
|
10
|
-
organizationAccess: [],
|
|
11
|
-
...overrides,
|
|
12
|
-
});
|
|
4
|
+
import { resolveSpaceAccess } from './spaceAccessResolver';
|
|
13
5
|
describe('resolveSpaceAccess', () => {
|
|
14
|
-
it('returns empty array for empty inputs', () => {
|
|
15
|
-
const result = resolveSpaceAccess(makeInput());
|
|
16
|
-
expect(result).toEqual([]);
|
|
17
|
-
});
|
|
18
|
-
describe('admin override', () => {
|
|
19
|
-
it('org admin gets space ADMIN', () => {
|
|
20
|
-
const result = resolveSpaceAccess(makeInput({
|
|
21
|
-
organizationAccess: [
|
|
22
|
-
{
|
|
23
|
-
userUuid: 'user-1',
|
|
24
|
-
spaceUuid: 'space-1',
|
|
25
|
-
role: OrganizationMemberRole.ADMIN,
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
}));
|
|
29
|
-
expect(result).toHaveLength(1);
|
|
30
|
-
expect(result[0].role).toBe(SpaceMemberRole.ADMIN);
|
|
31
|
-
expect(result[0].inheritedFrom).toBe('organization');
|
|
32
|
-
});
|
|
33
|
-
it('project admin gets space ADMIN', () => {
|
|
34
|
-
const result = resolveSpaceAccess(makeInput({
|
|
35
|
-
organizationAccess: [
|
|
36
|
-
{
|
|
37
|
-
userUuid: 'user-1',
|
|
38
|
-
spaceUuid: 'space-1',
|
|
39
|
-
role: OrganizationMemberRole.VIEWER,
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
projectAccess: [
|
|
43
|
-
{
|
|
44
|
-
userUuid: 'user-1',
|
|
45
|
-
spaceUuid: 'space-1',
|
|
46
|
-
role: ProjectMemberRole.ADMIN,
|
|
47
|
-
from: ProjectSpaceAccessOrigin.PROJECT_MEMBERSHIP,
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
}));
|
|
51
|
-
expect(result).toHaveLength(1);
|
|
52
|
-
expect(result[0].role).toBe(SpaceMemberRole.ADMIN);
|
|
53
|
-
});
|
|
54
|
-
it('group admin (project group) gets space ADMIN', () => {
|
|
55
|
-
const result = resolveSpaceAccess(makeInput({
|
|
56
|
-
organizationAccess: [
|
|
57
|
-
{
|
|
58
|
-
userUuid: 'user-1',
|
|
59
|
-
spaceUuid: 'space-1',
|
|
60
|
-
role: OrganizationMemberRole.VIEWER,
|
|
61
|
-
},
|
|
62
|
-
],
|
|
63
|
-
projectAccess: [
|
|
64
|
-
{
|
|
65
|
-
userUuid: 'user-1',
|
|
66
|
-
spaceUuid: 'space-1',
|
|
67
|
-
role: ProjectMemberRole.ADMIN,
|
|
68
|
-
from: ProjectSpaceAccessOrigin.GROUP_MEMBERSHIP,
|
|
69
|
-
},
|
|
70
|
-
],
|
|
71
|
-
}));
|
|
72
|
-
expect(result).toHaveLength(1);
|
|
73
|
-
expect(result[0].role).toBe(SpaceMemberRole.ADMIN);
|
|
74
|
-
});
|
|
75
|
-
it('admin can access private space even without direct access', () => {
|
|
76
|
-
const result = resolveSpaceAccess(makeInput({
|
|
77
|
-
inheritsFromOrgOrProject: false,
|
|
78
|
-
organizationAccess: [
|
|
79
|
-
{
|
|
80
|
-
userUuid: 'user-1',
|
|
81
|
-
spaceUuid: 'space-1',
|
|
82
|
-
role: OrganizationMemberRole.ADMIN,
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
}));
|
|
86
|
-
expect(result).toHaveLength(1);
|
|
87
|
-
expect(result[0].role).toBe(SpaceMemberRole.ADMIN);
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
describe('direct access', () => {
|
|
91
|
-
it('USER_ACCESS role used directly', () => {
|
|
92
|
-
const result = resolveSpaceAccess(makeInput({
|
|
93
|
-
organizationAccess: [
|
|
94
|
-
{
|
|
95
|
-
userUuid: 'user-1',
|
|
96
|
-
spaceUuid: 'space-1',
|
|
97
|
-
role: OrganizationMemberRole.VIEWER,
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
directAccess: [
|
|
101
|
-
{
|
|
102
|
-
userUuid: 'user-1',
|
|
103
|
-
spaceUuid: 'space-1',
|
|
104
|
-
role: SpaceMemberRole.EDITOR,
|
|
105
|
-
groupUuid: null,
|
|
106
|
-
from: DirectSpaceAccessOrigin.USER_ACCESS,
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
}));
|
|
110
|
-
expect(result).toHaveLength(1);
|
|
111
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
112
|
-
expect(result[0].hasDirectAccess).toBe(true);
|
|
113
|
-
});
|
|
114
|
-
it('GROUP_ACCESS role used when no user role', () => {
|
|
115
|
-
const result = resolveSpaceAccess(makeInput({
|
|
116
|
-
organizationAccess: [
|
|
117
|
-
{
|
|
118
|
-
userUuid: 'user-1',
|
|
119
|
-
spaceUuid: 'space-1',
|
|
120
|
-
role: OrganizationMemberRole.VIEWER,
|
|
121
|
-
},
|
|
122
|
-
],
|
|
123
|
-
directAccess: [
|
|
124
|
-
{
|
|
125
|
-
userUuid: 'user-1',
|
|
126
|
-
spaceUuid: 'space-1',
|
|
127
|
-
role: SpaceMemberRole.EDITOR,
|
|
128
|
-
groupUuid: 'group-1',
|
|
129
|
-
from: DirectSpaceAccessOrigin.GROUP_ACCESS,
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
}));
|
|
133
|
-
expect(result).toHaveLength(1);
|
|
134
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
135
|
-
expect(result[0].hasDirectAccess).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
it('user + group direct access: user role wins when higher', () => {
|
|
138
|
-
const result = resolveSpaceAccess(makeInput({
|
|
139
|
-
organizationAccess: [
|
|
140
|
-
{
|
|
141
|
-
userUuid: 'user-1',
|
|
142
|
-
spaceUuid: 'space-1',
|
|
143
|
-
role: OrganizationMemberRole.VIEWER,
|
|
144
|
-
},
|
|
145
|
-
],
|
|
146
|
-
directAccess: [
|
|
147
|
-
{
|
|
148
|
-
userUuid: 'user-1',
|
|
149
|
-
spaceUuid: 'space-1',
|
|
150
|
-
role: SpaceMemberRole.EDITOR,
|
|
151
|
-
groupUuid: null,
|
|
152
|
-
from: DirectSpaceAccessOrigin.USER_ACCESS,
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
userUuid: 'user-1',
|
|
156
|
-
spaceUuid: 'space-1',
|
|
157
|
-
role: SpaceMemberRole.VIEWER,
|
|
158
|
-
groupUuid: 'group-1',
|
|
159
|
-
from: DirectSpaceAccessOrigin.GROUP_ACCESS,
|
|
160
|
-
},
|
|
161
|
-
],
|
|
162
|
-
}));
|
|
163
|
-
expect(result).toHaveLength(1);
|
|
164
|
-
// User access takes precedence over group access
|
|
165
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
describe('public space inheritance', () => {
|
|
169
|
-
it('viewer gets viewer space role', () => {
|
|
170
|
-
const result = resolveSpaceAccess(makeInput({
|
|
171
|
-
inheritsFromOrgOrProject: true,
|
|
172
|
-
organizationAccess: [
|
|
173
|
-
{
|
|
174
|
-
userUuid: 'user-1',
|
|
175
|
-
spaceUuid: 'space-1',
|
|
176
|
-
role: OrganizationMemberRole.VIEWER,
|
|
177
|
-
},
|
|
178
|
-
],
|
|
179
|
-
}));
|
|
180
|
-
expect(result).toHaveLength(1);
|
|
181
|
-
expect(result[0].role).toBe(SpaceMemberRole.VIEWER);
|
|
182
|
-
expect(result[0].hasDirectAccess).toBe(false);
|
|
183
|
-
expect(result[0].inheritedFrom).toBe('organization');
|
|
184
|
-
});
|
|
185
|
-
it('editor gets editor space role', () => {
|
|
186
|
-
const result = resolveSpaceAccess(makeInput({
|
|
187
|
-
inheritsFromOrgOrProject: true,
|
|
188
|
-
organizationAccess: [
|
|
189
|
-
{
|
|
190
|
-
userUuid: 'user-1',
|
|
191
|
-
spaceUuid: 'space-1',
|
|
192
|
-
role: OrganizationMemberRole.EDITOR,
|
|
193
|
-
},
|
|
194
|
-
],
|
|
195
|
-
}));
|
|
196
|
-
expect(result).toHaveLength(1);
|
|
197
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
198
|
-
});
|
|
199
|
-
it('developer gets editor space role', () => {
|
|
200
|
-
const result = resolveSpaceAccess(makeInput({
|
|
201
|
-
inheritsFromOrgOrProject: true,
|
|
202
|
-
organizationAccess: [
|
|
203
|
-
{
|
|
204
|
-
userUuid: 'user-1',
|
|
205
|
-
spaceUuid: 'space-1',
|
|
206
|
-
role: OrganizationMemberRole.DEVELOPER,
|
|
207
|
-
},
|
|
208
|
-
],
|
|
209
|
-
}));
|
|
210
|
-
expect(result).toHaveLength(1);
|
|
211
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
212
|
-
});
|
|
213
|
-
it('interactive_viewer gets viewer space role', () => {
|
|
214
|
-
const result = resolveSpaceAccess(makeInput({
|
|
215
|
-
inheritsFromOrgOrProject: true,
|
|
216
|
-
organizationAccess: [
|
|
217
|
-
{
|
|
218
|
-
userUuid: 'user-1',
|
|
219
|
-
spaceUuid: 'space-1',
|
|
220
|
-
role: OrganizationMemberRole.INTERACTIVE_VIEWER,
|
|
221
|
-
},
|
|
222
|
-
],
|
|
223
|
-
}));
|
|
224
|
-
expect(result).toHaveLength(1);
|
|
225
|
-
expect(result[0].role).toBe(SpaceMemberRole.VIEWER);
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
describe('private space exclusion', () => {
|
|
229
|
-
it('non-admin without direct access excluded from private space', () => {
|
|
230
|
-
const result = resolveSpaceAccess(makeInput({
|
|
231
|
-
inheritsFromOrgOrProject: false,
|
|
232
|
-
organizationAccess: [
|
|
233
|
-
{
|
|
234
|
-
userUuid: 'user-1',
|
|
235
|
-
spaceUuid: 'space-1',
|
|
236
|
-
role: OrganizationMemberRole.EDITOR,
|
|
237
|
-
},
|
|
238
|
-
],
|
|
239
|
-
}));
|
|
240
|
-
expect(result).toHaveLength(0);
|
|
241
|
-
});
|
|
242
|
-
it('private space with direct access works', () => {
|
|
243
|
-
const result = resolveSpaceAccess(makeInput({
|
|
244
|
-
inheritsFromOrgOrProject: false,
|
|
245
|
-
organizationAccess: [
|
|
246
|
-
{
|
|
247
|
-
userUuid: 'user-1',
|
|
248
|
-
spaceUuid: 'space-1',
|
|
249
|
-
role: OrganizationMemberRole.VIEWER,
|
|
250
|
-
},
|
|
251
|
-
],
|
|
252
|
-
directAccess: [
|
|
253
|
-
{
|
|
254
|
-
userUuid: 'user-1',
|
|
255
|
-
spaceUuid: 'space-1',
|
|
256
|
-
role: SpaceMemberRole.EDITOR,
|
|
257
|
-
groupUuid: null,
|
|
258
|
-
from: DirectSpaceAccessOrigin.USER_ACCESS,
|
|
259
|
-
},
|
|
260
|
-
],
|
|
261
|
-
}));
|
|
262
|
-
expect(result).toHaveLength(1);
|
|
263
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
describe('org MEMBER role', () => {
|
|
267
|
-
it('org MEMBER with no other access is excluded', () => {
|
|
268
|
-
const result = resolveSpaceAccess(makeInput({
|
|
269
|
-
inheritsFromOrgOrProject: true,
|
|
270
|
-
organizationAccess: [
|
|
271
|
-
{
|
|
272
|
-
userUuid: 'user-1',
|
|
273
|
-
spaceUuid: 'space-1',
|
|
274
|
-
role: OrganizationMemberRole.MEMBER,
|
|
275
|
-
},
|
|
276
|
-
],
|
|
277
|
-
}));
|
|
278
|
-
// MEMBER converts to undefined project role, so no highest role → excluded
|
|
279
|
-
expect(result).toHaveLength(0);
|
|
280
|
-
});
|
|
281
|
-
it('org MEMBER with project access is included', () => {
|
|
282
|
-
const result = resolveSpaceAccess(makeInput({
|
|
283
|
-
inheritsFromOrgOrProject: true,
|
|
284
|
-
organizationAccess: [
|
|
285
|
-
{
|
|
286
|
-
userUuid: 'user-1',
|
|
287
|
-
spaceUuid: 'space-1',
|
|
288
|
-
role: OrganizationMemberRole.VIEWER,
|
|
289
|
-
},
|
|
290
|
-
],
|
|
291
|
-
projectAccess: [
|
|
292
|
-
{
|
|
293
|
-
userUuid: 'user-1',
|
|
294
|
-
spaceUuid: 'space-1',
|
|
295
|
-
role: ProjectMemberRole.EDITOR,
|
|
296
|
-
from: ProjectSpaceAccessOrigin.PROJECT_MEMBERSHIP,
|
|
297
|
-
},
|
|
298
|
-
],
|
|
299
|
-
}));
|
|
300
|
-
expect(result).toHaveLength(1);
|
|
301
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
describe('multiple group roles', () => {
|
|
305
|
-
it('highest group role wins', () => {
|
|
306
|
-
const result = resolveSpaceAccess(makeInput({
|
|
307
|
-
inheritsFromOrgOrProject: true,
|
|
308
|
-
organizationAccess: [
|
|
309
|
-
{
|
|
310
|
-
userUuid: 'user-1',
|
|
311
|
-
spaceUuid: 'space-1',
|
|
312
|
-
role: OrganizationMemberRole.VIEWER,
|
|
313
|
-
},
|
|
314
|
-
],
|
|
315
|
-
projectAccess: [
|
|
316
|
-
{
|
|
317
|
-
userUuid: 'user-1',
|
|
318
|
-
spaceUuid: 'space-1',
|
|
319
|
-
role: ProjectMemberRole.VIEWER,
|
|
320
|
-
from: ProjectSpaceAccessOrigin.GROUP_MEMBERSHIP,
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
userUuid: 'user-1',
|
|
324
|
-
spaceUuid: 'space-1',
|
|
325
|
-
role: ProjectMemberRole.EDITOR,
|
|
326
|
-
from: ProjectSpaceAccessOrigin.GROUP_MEMBERSHIP,
|
|
327
|
-
},
|
|
328
|
-
],
|
|
329
|
-
}));
|
|
330
|
-
expect(result).toHaveLength(1);
|
|
331
|
-
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
describe('inheritedFrom metadata', () => {
|
|
335
|
-
it('reports organization when org role is highest', () => {
|
|
336
|
-
const result = resolveSpaceAccess(makeInput({
|
|
337
|
-
organizationAccess: [
|
|
338
|
-
{
|
|
339
|
-
userUuid: 'user-1',
|
|
340
|
-
spaceUuid: 'space-1',
|
|
341
|
-
role: OrganizationMemberRole.EDITOR,
|
|
342
|
-
},
|
|
343
|
-
],
|
|
344
|
-
}));
|
|
345
|
-
expect(result[0].inheritedFrom).toBe('organization');
|
|
346
|
-
});
|
|
347
|
-
it('reports project when project role is highest', () => {
|
|
348
|
-
const result = resolveSpaceAccess(makeInput({
|
|
349
|
-
organizationAccess: [
|
|
350
|
-
{
|
|
351
|
-
userUuid: 'user-1',
|
|
352
|
-
spaceUuid: 'space-1',
|
|
353
|
-
role: OrganizationMemberRole.VIEWER,
|
|
354
|
-
},
|
|
355
|
-
],
|
|
356
|
-
projectAccess: [
|
|
357
|
-
{
|
|
358
|
-
userUuid: 'user-1',
|
|
359
|
-
spaceUuid: 'space-1',
|
|
360
|
-
role: ProjectMemberRole.EDITOR,
|
|
361
|
-
from: ProjectSpaceAccessOrigin.PROJECT_MEMBERSHIP,
|
|
362
|
-
},
|
|
363
|
-
],
|
|
364
|
-
}));
|
|
365
|
-
expect(result[0].inheritedFrom).toBe('project');
|
|
366
|
-
});
|
|
367
|
-
it('reports group when group project role is highest', () => {
|
|
368
|
-
const result = resolveSpaceAccess(makeInput({
|
|
369
|
-
organizationAccess: [
|
|
370
|
-
{
|
|
371
|
-
userUuid: 'user-1',
|
|
372
|
-
spaceUuid: 'space-1',
|
|
373
|
-
role: OrganizationMemberRole.VIEWER,
|
|
374
|
-
},
|
|
375
|
-
],
|
|
376
|
-
projectAccess: [
|
|
377
|
-
{
|
|
378
|
-
userUuid: 'user-1',
|
|
379
|
-
spaceUuid: 'space-1',
|
|
380
|
-
role: ProjectMemberRole.DEVELOPER,
|
|
381
|
-
from: ProjectSpaceAccessOrigin.GROUP_MEMBERSHIP,
|
|
382
|
-
},
|
|
383
|
-
],
|
|
384
|
-
}));
|
|
385
|
-
expect(result[0].inheritedFrom).toBe('group');
|
|
386
|
-
});
|
|
387
|
-
it('reports space_group when space group access role is highest', () => {
|
|
388
|
-
const result = resolveSpaceAccess(makeInput({
|
|
389
|
-
organizationAccess: [
|
|
390
|
-
{
|
|
391
|
-
userUuid: 'user-1',
|
|
392
|
-
spaceUuid: 'space-1',
|
|
393
|
-
role: OrganizationMemberRole.VIEWER,
|
|
394
|
-
},
|
|
395
|
-
],
|
|
396
|
-
directAccess: [
|
|
397
|
-
{
|
|
398
|
-
userUuid: 'user-1',
|
|
399
|
-
spaceUuid: 'space-1',
|
|
400
|
-
role: SpaceMemberRole.EDITOR,
|
|
401
|
-
groupUuid: 'group-1',
|
|
402
|
-
from: DirectSpaceAccessOrigin.GROUP_ACCESS,
|
|
403
|
-
},
|
|
404
|
-
],
|
|
405
|
-
}));
|
|
406
|
-
expect(result[0].inheritedFrom).toBe('space_group');
|
|
407
|
-
});
|
|
408
|
-
it('reports org access when org access is highest', () => {
|
|
409
|
-
const result = resolveSpaceAccess(makeInput({
|
|
410
|
-
organizationAccess: [
|
|
411
|
-
{
|
|
412
|
-
userUuid: 'user-1',
|
|
413
|
-
spaceUuid: 'space-1',
|
|
414
|
-
role: OrganizationMemberRole.DEVELOPER,
|
|
415
|
-
},
|
|
416
|
-
],
|
|
417
|
-
directAccess: [
|
|
418
|
-
{
|
|
419
|
-
userUuid: 'user-1',
|
|
420
|
-
spaceUuid: 'space-1',
|
|
421
|
-
role: SpaceMemberRole.VIEWER,
|
|
422
|
-
groupUuid: null,
|
|
423
|
-
from: DirectSpaceAccessOrigin.USER_ACCESS,
|
|
424
|
-
},
|
|
425
|
-
],
|
|
426
|
-
}));
|
|
427
|
-
expect(result[0].inheritedFrom).toBe('organization');
|
|
428
|
-
// Direct user access takes precedence over inherited org role
|
|
429
|
-
// for the space role, even if the org role is higher.
|
|
430
|
-
// The org source is reflected in inheritedFrom/inheritedRole.
|
|
431
|
-
expect(result[0].role).toBe(SpaceMemberRole.VIEWER);
|
|
432
|
-
});
|
|
433
|
-
});
|
|
434
|
-
describe('projectRole field', () => {
|
|
435
|
-
it('only considers org + direct project membership (not groups)', () => {
|
|
436
|
-
const result = resolveSpaceAccess(makeInput({
|
|
437
|
-
organizationAccess: [
|
|
438
|
-
{
|
|
439
|
-
userUuid: 'user-1',
|
|
440
|
-
spaceUuid: 'space-1',
|
|
441
|
-
role: OrganizationMemberRole.VIEWER,
|
|
442
|
-
},
|
|
443
|
-
],
|
|
444
|
-
projectAccess: [
|
|
445
|
-
{
|
|
446
|
-
userUuid: 'user-1',
|
|
447
|
-
spaceUuid: 'space-1',
|
|
448
|
-
role: ProjectMemberRole.DEVELOPER,
|
|
449
|
-
from: ProjectSpaceAccessOrigin.GROUP_MEMBERSHIP,
|
|
450
|
-
},
|
|
451
|
-
],
|
|
452
|
-
}));
|
|
453
|
-
// projectRole should be VIEWER (from org), not DEVELOPER (from group)
|
|
454
|
-
expect(result[0].projectRole).toBe(ProjectMemberRole.VIEWER);
|
|
455
|
-
});
|
|
456
|
-
it('includes direct project membership in projectRole', () => {
|
|
457
|
-
const result = resolveSpaceAccess(makeInput({
|
|
458
|
-
organizationAccess: [
|
|
459
|
-
{
|
|
460
|
-
userUuid: 'user-1',
|
|
461
|
-
spaceUuid: 'space-1',
|
|
462
|
-
role: OrganizationMemberRole.VIEWER,
|
|
463
|
-
},
|
|
464
|
-
],
|
|
465
|
-
projectAccess: [
|
|
466
|
-
{
|
|
467
|
-
userUuid: 'user-1',
|
|
468
|
-
spaceUuid: 'space-1',
|
|
469
|
-
role: ProjectMemberRole.EDITOR,
|
|
470
|
-
from: ProjectSpaceAccessOrigin.PROJECT_MEMBERSHIP,
|
|
471
|
-
},
|
|
472
|
-
],
|
|
473
|
-
}));
|
|
474
|
-
expect(result[0].projectRole).toBe(ProjectMemberRole.EDITOR);
|
|
475
|
-
});
|
|
476
|
-
});
|
|
477
|
-
describe('multiple users', () => {
|
|
478
|
-
it('resolves access for multiple users independently', () => {
|
|
479
|
-
const orgAccess = [
|
|
480
|
-
{
|
|
481
|
-
userUuid: 'user-1',
|
|
482
|
-
spaceUuid: 'space-1',
|
|
483
|
-
role: OrganizationMemberRole.EDITOR,
|
|
484
|
-
},
|
|
485
|
-
{
|
|
486
|
-
userUuid: 'user-2',
|
|
487
|
-
spaceUuid: 'space-1',
|
|
488
|
-
role: OrganizationMemberRole.VIEWER,
|
|
489
|
-
},
|
|
490
|
-
];
|
|
491
|
-
const directAccess = [
|
|
492
|
-
{
|
|
493
|
-
userUuid: 'user-2',
|
|
494
|
-
spaceUuid: 'space-1',
|
|
495
|
-
role: SpaceMemberRole.ADMIN,
|
|
496
|
-
groupUuid: null,
|
|
497
|
-
from: DirectSpaceAccessOrigin.USER_ACCESS,
|
|
498
|
-
},
|
|
499
|
-
];
|
|
500
|
-
const projectAccess = [];
|
|
501
|
-
const result = resolveSpaceAccess(makeInput({
|
|
502
|
-
organizationAccess: orgAccess,
|
|
503
|
-
directAccess,
|
|
504
|
-
projectAccess,
|
|
505
|
-
}));
|
|
506
|
-
expect(result).toHaveLength(2);
|
|
507
|
-
const user1 = result.find((r) => r.userUuid === 'user-1');
|
|
508
|
-
const user2 = result.find((r) => r.userUuid === 'user-2');
|
|
509
|
-
expect(user1?.role).toBe(SpaceMemberRole.EDITOR);
|
|
510
|
-
expect(user1?.hasDirectAccess).toBe(false);
|
|
511
|
-
expect(user2?.role).toBe(SpaceMemberRole.ADMIN);
|
|
512
|
-
expect(user2?.hasDirectAccess).toBe(true);
|
|
513
|
-
});
|
|
514
|
-
});
|
|
515
|
-
});
|
|
516
|
-
describe('resolveSpaceAccessWithInheritance', () => {
|
|
517
6
|
const makeChainInput = (overrides = {}) => ({
|
|
518
7
|
spaceUuid: 'child-space',
|
|
519
8
|
inheritsFromOrgOrProject: true,
|
|
@@ -523,12 +12,12 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
523
12
|
...overrides,
|
|
524
13
|
});
|
|
525
14
|
it('returns empty array for empty inputs', () => {
|
|
526
|
-
const result =
|
|
15
|
+
const result = resolveSpaceAccess(makeChainInput());
|
|
527
16
|
expect(result).toEqual([]);
|
|
528
17
|
});
|
|
529
18
|
describe('single-space chain (backward compat)', () => {
|
|
530
19
|
it('org admin gets space ADMIN', () => {
|
|
531
|
-
const result =
|
|
20
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
532
21
|
chainDirectAccess: [
|
|
533
22
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
534
23
|
],
|
|
@@ -544,7 +33,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
544
33
|
expect(result[0].role).toBe(SpaceMemberRole.ADMIN);
|
|
545
34
|
});
|
|
546
35
|
it('direct user access on single space resolves correctly', () => {
|
|
547
|
-
const result =
|
|
36
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
548
37
|
chainDirectAccess: [
|
|
549
38
|
{
|
|
550
39
|
spaceUuid: 'child-space',
|
|
@@ -574,7 +63,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
574
63
|
});
|
|
575
64
|
describe('most permissive wins across chain', () => {
|
|
576
65
|
it('USER_ACCESS EDITOR on parent beats USER_ACCESS VIEWER on child', () => {
|
|
577
|
-
const result =
|
|
66
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
578
67
|
chainDirectAccess: [
|
|
579
68
|
{
|
|
580
69
|
spaceUuid: 'child-space',
|
|
@@ -614,7 +103,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
614
103
|
expect(result[0].hasDirectAccess).toBe(true);
|
|
615
104
|
});
|
|
616
105
|
it('GROUP_ACCESS EDITOR on parent beats USER_ACCESS VIEWER on child', () => {
|
|
617
|
-
const result =
|
|
106
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
618
107
|
chainDirectAccess: [
|
|
619
108
|
{
|
|
620
109
|
spaceUuid: 'child-space',
|
|
@@ -653,7 +142,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
653
142
|
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
654
143
|
});
|
|
655
144
|
it('USER_ACCESS EDITOR on child already wins (child is higher)', () => {
|
|
656
|
-
const result =
|
|
145
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
657
146
|
chainDirectAccess: [
|
|
658
147
|
{
|
|
659
148
|
spaceUuid: 'child-space',
|
|
@@ -692,7 +181,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
692
181
|
expect(result[0].role).toBe(SpaceMemberRole.EDITOR);
|
|
693
182
|
});
|
|
694
183
|
it('three-level chain: grandparent ADMIN wins over child VIEWER', () => {
|
|
695
|
-
const result =
|
|
184
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
696
185
|
chainDirectAccess: [
|
|
697
186
|
{
|
|
698
187
|
spaceUuid: 'child-space',
|
|
@@ -737,7 +226,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
737
226
|
});
|
|
738
227
|
describe('hasDirectAccess', () => {
|
|
739
228
|
it('is false when user has direct access only on parent (inherited)', () => {
|
|
740
|
-
const result =
|
|
229
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
741
230
|
chainDirectAccess: [
|
|
742
231
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
743
232
|
{
|
|
@@ -765,7 +254,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
765
254
|
expect(result[0].hasDirectAccess).toBe(false);
|
|
766
255
|
});
|
|
767
256
|
it('is true when user has direct access on the leaf space', () => {
|
|
768
|
-
const result =
|
|
257
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
769
258
|
chainDirectAccess: [
|
|
770
259
|
{
|
|
771
260
|
spaceUuid: 'child-space',
|
|
@@ -792,7 +281,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
792
281
|
expect(result[0].hasDirectAccess).toBe(true);
|
|
793
282
|
});
|
|
794
283
|
it('is false when user has group access only on parent', () => {
|
|
795
|
-
const result =
|
|
284
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
796
285
|
chainDirectAccess: [
|
|
797
286
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
798
287
|
{
|
|
@@ -821,7 +310,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
821
310
|
expect(result[0].inheritedFrom).toBe('parent_space');
|
|
822
311
|
});
|
|
823
312
|
it('is false when user has only project/org access', () => {
|
|
824
|
-
const result =
|
|
313
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
825
314
|
chainDirectAccess: [
|
|
826
315
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
827
316
|
],
|
|
@@ -839,7 +328,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
839
328
|
});
|
|
840
329
|
describe('inheritedFrom metadata', () => {
|
|
841
330
|
it('reports parent_space when winning role is from ancestor', () => {
|
|
842
|
-
const result =
|
|
331
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
843
332
|
chainDirectAccess: [
|
|
844
333
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
845
334
|
{
|
|
@@ -867,7 +356,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
867
356
|
expect(result[0].inheritedFrom).toBe('parent_space');
|
|
868
357
|
});
|
|
869
358
|
it('reports parent_space when group access is from ancestor', () => {
|
|
870
|
-
const result =
|
|
359
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
871
360
|
chainDirectAccess: [
|
|
872
361
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
873
362
|
{
|
|
@@ -896,7 +385,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
896
385
|
expect(result[0].hasDirectAccess).toBe(false);
|
|
897
386
|
});
|
|
898
387
|
it('does not report parent_space when winning role is from leaf', () => {
|
|
899
|
-
const result =
|
|
388
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
900
389
|
chainDirectAccess: [
|
|
901
390
|
{
|
|
902
391
|
spaceUuid: 'child-space',
|
|
@@ -925,7 +414,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
925
414
|
});
|
|
926
415
|
describe('private chain', () => {
|
|
927
416
|
it('no access without direct access on private chain', () => {
|
|
928
|
-
const result =
|
|
417
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
929
418
|
inheritsFromOrgOrProject: false,
|
|
930
419
|
chainDirectAccess: [
|
|
931
420
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
@@ -949,7 +438,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
949
438
|
expect(result).toHaveLength(0);
|
|
950
439
|
});
|
|
951
440
|
it('admin without direct access is excluded (CASL handles admin access)', () => {
|
|
952
|
-
const result =
|
|
441
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
953
442
|
inheritsFromOrgOrProject: false,
|
|
954
443
|
chainDirectAccess: [
|
|
955
444
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
@@ -965,7 +454,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
965
454
|
expect(result).toHaveLength(0);
|
|
966
455
|
});
|
|
967
456
|
it('direct access on parent grants access on private child', () => {
|
|
968
|
-
const result =
|
|
457
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
969
458
|
inheritsFromOrgOrProject: false,
|
|
970
459
|
chainDirectAccess: [
|
|
971
460
|
{ spaceUuid: 'child-space', directAccess: [] },
|
|
@@ -996,7 +485,7 @@ describe('resolveSpaceAccessWithInheritance', () => {
|
|
|
996
485
|
});
|
|
997
486
|
describe('multiple users', () => {
|
|
998
487
|
it('resolves each user independently', () => {
|
|
999
|
-
const result =
|
|
488
|
+
const result = resolveSpaceAccess(makeChainInput({
|
|
1000
489
|
chainDirectAccess: [
|
|
1001
490
|
{
|
|
1002
491
|
spaceUuid: 'child-space',
|