@tuturuuu/utils 0.28.0 → 0.29.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/CHANGELOG.md +30 -0
- package/biome.json +1 -1
- package/package.json +17 -16
- package/src/__tests__/api-proxy-guard.test.ts +20 -27
- package/src/__tests__/app-url.test.ts +1 -0
- package/src/__tests__/workspace-principal-resolution.test.ts +34 -0
- package/src/api-proxy-guard.ts +0 -15
- package/src/commercial-comparison-0.ts +294 -0
- package/src/commercial-comparison-1.ts +283 -0
- package/src/commercial-comparison-2.ts +262 -0
- package/src/commercial-comparison-types.ts +20 -0
- package/src/commercial-comparison.test.ts +32 -0
- package/src/commercial-comparison.ts +96 -0
- package/src/coordination-protocol.ts +61 -0
- package/src/coordination.test.ts +84 -0
- package/src/coordination.ts +57 -0
- package/src/feature-tier-policy.ts +26 -0
- package/src/internal-domains.ts +3 -0
- package/src/launchable-apps.ts +13 -0
- package/src/meet-creation-policy.test.ts +11 -0
- package/src/meet-creation-policy.ts +9 -3
- package/src/meet-duration.ts +71 -0
- package/src/meet-hosting.test.ts +58 -0
- package/src/meet-hosting.ts +19 -0
- package/src/meeting-invitations.test.ts +102 -0
- package/src/meeting-invitations.ts +81 -0
- package/src/onboarding.ts +1 -0
- package/src/platform-release.test.ts +1 -1
- package/src/platform-release.ts +1 -1
- package/src/portless.ts +1 -0
- package/src/task-helper/task-sort.test.ts +22 -3
- package/src/task-helper/task-sort.ts +33 -3
- package/src/workspace-helper.ts +3 -3
- package/src/workspace-limits.ts +1 -1
|
@@ -22,7 +22,7 @@ describe('sortTasksByCriterion', () => {
|
|
|
22
22
|
expect(parseTaskSortBy(null)).toBeUndefined();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
it('sorts every priority direction with unset priorities
|
|
25
|
+
it('sorts every priority direction with unset priorities first by default', () => {
|
|
26
26
|
const tasks = [
|
|
27
27
|
task('none'),
|
|
28
28
|
task('high', { priority: 'high' }),
|
|
@@ -33,12 +33,31 @@ describe('sortTasksByCriterion', () => {
|
|
|
33
33
|
|
|
34
34
|
expect(
|
|
35
35
|
sortTasksByCriterion(tasks, 'priority-high').map(({ id }) => id)
|
|
36
|
-
).toEqual(['critical', 'high', 'normal', 'low'
|
|
36
|
+
).toEqual(['none', 'critical', 'high', 'normal', 'low']);
|
|
37
37
|
expect(
|
|
38
38
|
sortTasksByCriterion(tasks, 'priority-low').map(({ id }) => id)
|
|
39
|
-
).toEqual(['low', 'normal', 'high', 'critical'
|
|
39
|
+
).toEqual(['none', 'low', 'normal', 'high', 'critical']);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
it.each(['priority-high', 'priority-low'] as const)(
|
|
43
|
+
'keeps null and undefined priorities last when requested: %s',
|
|
44
|
+
(sortBy) => {
|
|
45
|
+
const tasks = [
|
|
46
|
+
task('null', { priority: null }),
|
|
47
|
+
task('set', { priority: 'high' }),
|
|
48
|
+
task('undefined'),
|
|
49
|
+
];
|
|
50
|
+
expect(
|
|
51
|
+
sortTasksByCriterion(tasks, sortBy, 'last').map((t) => t.id)
|
|
52
|
+
).toEqual(['set', 'null', 'undefined']);
|
|
53
|
+
expect(sortTasksByCriterion(tasks, sortBy).map((t) => t.id)).toEqual([
|
|
54
|
+
'null',
|
|
55
|
+
'undefined',
|
|
56
|
+
'set',
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
42
61
|
it('keeps missing due dates and estimations last in both directions', () => {
|
|
43
62
|
const tasks = [
|
|
44
63
|
task('none'),
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { TaskPriority } from '@tuturuuu/types/primitives/Priority';
|
|
2
2
|
|
|
3
|
+
export const TASK_UNPRIORITIZED_POSITION_CONFIG_ID =
|
|
4
|
+
'TASK_UNPRIORITIZED_POSITION';
|
|
5
|
+
export type UnprioritizedPosition = 'first' | 'last';
|
|
6
|
+
export function normalizeUnprioritizedPosition(
|
|
7
|
+
value: unknown
|
|
8
|
+
): UnprioritizedPosition {
|
|
9
|
+
return value === 'last' ? 'last' : 'first';
|
|
10
|
+
}
|
|
11
|
+
|
|
3
12
|
export type TaskSortBy =
|
|
4
13
|
| 'name-asc'
|
|
5
14
|
| 'name-desc'
|
|
@@ -78,11 +87,29 @@ function compareCreatedFallback(a: SortableTask, b: SortableTask) {
|
|
|
78
87
|
return created || a.id.localeCompare(b.id);
|
|
79
88
|
}
|
|
80
89
|
|
|
90
|
+
export function compareUnprioritizedPlacement(
|
|
91
|
+
a: TaskPriority | null | undefined,
|
|
92
|
+
b: TaskPriority | null | undefined,
|
|
93
|
+
position: UnprioritizedPosition = 'first'
|
|
94
|
+
) {
|
|
95
|
+
if ((a == null) === (b == null)) return 0;
|
|
96
|
+
return (a == null ? -1 : 1) * (position === 'first' ? 1 : -1);
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
export function compareTasksByCriterion(
|
|
82
100
|
a: SortableTask,
|
|
83
101
|
b: SortableTask,
|
|
84
|
-
sortBy: TaskSortBy
|
|
102
|
+
sortBy: TaskSortBy,
|
|
103
|
+
unprioritizedPosition: UnprioritizedPosition = 'first'
|
|
85
104
|
) {
|
|
105
|
+
if (sortBy === 'priority-high' || sortBy === 'priority-low') {
|
|
106
|
+
const placement = compareUnprioritizedPlacement(
|
|
107
|
+
a.priority,
|
|
108
|
+
b.priority,
|
|
109
|
+
unprioritizedPosition
|
|
110
|
+
);
|
|
111
|
+
if (placement) return placement;
|
|
112
|
+
}
|
|
86
113
|
let result = 0;
|
|
87
114
|
|
|
88
115
|
switch (sortBy) {
|
|
@@ -155,8 +182,11 @@ export function compareTasksByCriterion(
|
|
|
155
182
|
|
|
156
183
|
export function sortTasksByCriterion<T extends SortableTask>(
|
|
157
184
|
tasks: readonly T[],
|
|
158
|
-
sortBy: TaskSortBy | null | undefined
|
|
185
|
+
sortBy: TaskSortBy | null | undefined,
|
|
186
|
+
unprioritizedPosition: UnprioritizedPosition = 'first'
|
|
159
187
|
) {
|
|
160
188
|
if (!sortBy) return [...tasks];
|
|
161
|
-
return [...tasks].sort((a, b) =>
|
|
189
|
+
return [...tasks].sort((a, b) =>
|
|
190
|
+
compareTasksByCriterion(a, b, sortBy, unprioritizedPosition)
|
|
191
|
+
);
|
|
162
192
|
}
|
package/src/workspace-helper.ts
CHANGED
|
@@ -702,7 +702,6 @@ export async function resolveWorkspaceIdForPrincipal({
|
|
|
702
702
|
if (wsId.trim().toLowerCase() !== PERSONAL_WORKSPACE_SLUG) {
|
|
703
703
|
return normalizeWorkspaceId(wsId, authorizationClient);
|
|
704
704
|
}
|
|
705
|
-
|
|
706
705
|
const { data: creatorWorkspace, error: creatorWorkspaceError } =
|
|
707
706
|
await authorizationClient
|
|
708
707
|
.from('workspaces')
|
|
@@ -710,7 +709,6 @@ export async function resolveWorkspaceIdForPrincipal({
|
|
|
710
709
|
.eq('personal', true)
|
|
711
710
|
.eq('creator_id', principal.id)
|
|
712
711
|
.maybeSingle();
|
|
713
|
-
|
|
714
712
|
if (!creatorWorkspaceError && creatorWorkspace?.id) {
|
|
715
713
|
return creatorWorkspace.id;
|
|
716
714
|
}
|
|
@@ -725,7 +723,9 @@ export async function resolveWorkspaceIdForPrincipal({
|
|
|
725
723
|
.maybeSingle();
|
|
726
724
|
|
|
727
725
|
if (memberWorkspaceError || !memberWorkspace?.id) {
|
|
728
|
-
throw
|
|
726
|
+
throw creatorWorkspaceError || memberWorkspaceError
|
|
727
|
+
? new WorkspaceResolutionError('Personal workspace lookup failed')
|
|
728
|
+
: new WorkspaceNotFoundError('Personal workspace not found');
|
|
729
729
|
}
|
|
730
730
|
|
|
731
731
|
return memberWorkspace.id;
|
package/src/workspace-limits.ts
CHANGED
|
@@ -55,7 +55,7 @@ export async function checkWorkspaceCreationLimit(
|
|
|
55
55
|
canCreate: false,
|
|
56
56
|
currentCount,
|
|
57
57
|
limit: MAX_WORKSPACES_FOR_FREE_USERS,
|
|
58
|
-
errorMessage: `You have reached the maximum limit of ${MAX_WORKSPACES_FOR_FREE_USERS} workspaces.
|
|
58
|
+
errorMessage: `You have reached the maximum limit of ${MAX_WORKSPACES_FOR_FREE_USERS} workspaces. Upgrading does not increase this account limit. Contact the Tuturuuu team if you need more workspaces.`,
|
|
59
59
|
errorCode: WORKSPACE_LIMIT_ERROR_CODE,
|
|
60
60
|
};
|
|
61
61
|
}
|