@ossy/workspaces 1.17.3 → 3.0.2

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/README.md CHANGED
@@ -37,6 +37,10 @@ npm run build
37
37
 
38
38
  `@ossy/app` discovers the pages automatically by reading the `"ossy": { "src": "./src" }` field in this package's `package.json`.
39
39
 
40
+ ## Preview
41
+
42
+ Workspace pages are exercised in **`@ossy/app-test`** on the production build path. Open workspace routes from the sidebar or inspect capabilities at `/packages/workspaces`. See [`packages/app-test/README.md`](../app-test/README.md).
43
+
40
44
  ## Peer dependencies
41
45
 
42
46
  | Package | Version |
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ossy/workspaces",
3
3
  "description": "Workspaces feature package - create, select, and manage workspaces, users, and invitations",
4
- "version": "1.17.3",
4
+ "version": "3.0.2",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "module": "./src/index.js",
@@ -22,6 +22,10 @@
22
22
  "ossy": {
23
23
  "src": "./src"
24
24
  },
25
+ "dependencies": {
26
+ "@ossy/config": "^3.0.2",
27
+ "@ossy/schema": "^3.0.2"
28
+ },
25
29
  "peerDependencies": {
26
30
  "@ossy/design-system": ">=1.0.0",
27
31
  "@ossy/router-react": ">=1.0.0",
@@ -30,7 +34,6 @@
30
34
  },
31
35
  "devDependencies": {
32
36
  "@jest/globals": "^30.2.0",
33
- "@ossy/platform": "^1.39.3",
34
37
  "casual": "^1.6.2",
35
38
  "jest": "^30.2.0"
36
39
  },
@@ -42,5 +45,5 @@
42
45
  "/src",
43
46
  "README.md"
44
47
  ],
45
- "gitHead": "a0d89185a17f8de8ce328c3a648c108ff1d61d8f"
48
+ "gitHead": "f0a8af3c370bbaffe4f7388c14f9345a5c6c56e5"
46
49
  }
@@ -25,7 +25,7 @@ export const AuthenticationGuard = ({ children }) => {
25
25
  <View layout="off-center" style={{ height: '100%' }}>
26
26
  <Guide
27
27
  style={{ width: '100vw', maxWidth: '300px' }}
28
- slot="content"
28
+ data-region="content"
29
29
  title={t('authentication.guard.notAuthenticated.title')}
30
30
  text={t('authentication.guard.notAuthenticated.text')}
31
31
  />
@@ -36,7 +36,7 @@ export const AuthenticationGuard = ({ children }) => {
36
36
  <View layout="off-center" style={{ height: '100%' }}>
37
37
  <Guide
38
38
  style={{ width: '100vw', maxWidth: '300px' }}
39
- slot="content"
39
+ data-region="content"
40
40
  title={t('authentication.guard.error.title')}
41
41
  text={t('authentication.guard.error.text')}
42
42
  />
@@ -49,7 +49,7 @@ export const AuthenticationGuard = ({ children }) => {
49
49
  name="spinner"
50
50
  style={{ width: '64px', height: '64px' }}
51
51
  className="rotate fill-50"
52
- slot="content"
52
+ data-region="content"
53
53
  />
54
54
  </View>
55
55
  </Switch.Case>
package/src/Definition.js CHANGED
@@ -3,6 +3,6 @@ export const Definition = {
3
3
  title: 'Workspaces',
4
4
  description: 'Workspace lifecycle, members, invitations, and services.',
5
5
  icon: 'users',
6
- statuses: ['beta'],
6
+ status: ['beta'],
7
7
  entitlementRequired: false,
8
8
  }
@@ -13,7 +13,7 @@ export const metadata = {
13
13
  export const InvitationsPage = () => {
14
14
  return (
15
15
  <View layout="off-center-m" style={{ height: '100%' }}>
16
- <View slot="content" surface="primary" roundness="m" inset="m">
16
+ <View data-region="content" surface="primary" roundness="m" inset="m">
17
17
  <Invitations />
18
18
  </View>
19
19
  </View>
@@ -13,7 +13,7 @@ export const metadata = {
13
13
  export const InvitePage = () => {
14
14
  return (
15
15
  <View layout="off-center-m" style={{ height: '100%' }}>
16
- <View slot="content" surface="primary" roundness="m" inset="m">
16
+ <View data-region="content" surface="primary" roundness="m" inset="m">
17
17
  <Invite />
18
18
  </View>
19
19
  </View>
@@ -24,7 +24,7 @@ export const SelectWorkspacePage = () => {
24
24
  : asyncStatus
25
25
 
26
26
  const setWorkspace = workspaceId => {
27
- selectWorkspace(workspaceId, router.getHref('@home/home'))
27
+ selectWorkspace(workspaceId, router.getHref('@home') || '/')
28
28
  }
29
29
 
30
30
  return (
@@ -59,7 +59,7 @@ export const SelectWorkspacePage = () => {
59
59
  <Switch.Case match={[PageFlow.Error]}>
60
60
  <View layout="off-center" style={{ height: '100%' }}>
61
61
  <Guide
62
- slot="content"
62
+ data-region="content"
63
63
  style={{ width: '100vw', maxWidth: '500px' }}
64
64
  title={t('workspaces.select.errorTitle')}
65
65
  text={t('workspaces.select.errorText')}
@@ -74,7 +74,7 @@ export const SelectWorkspacePage = () => {
74
74
 
75
75
  <Switch.Case match={[PageFlow.Loading]}>
76
76
  <Icon
77
- slot="content"
77
+ data-region="content"
78
78
  name="spinner"
79
79
  style={{ width: '64px', height: '64px' }}
80
80
  className="rotate"
@@ -116,7 +116,7 @@ export const SelectWorkspacePage = () => {
116
116
  <Switch.Case match={[PageFlow.NoWorkspacesCreated]}>
117
117
  <View layout="vertical-top" style={{ flexGrow: '1' }}>
118
118
  <Guide
119
- slot="content"
119
+ data-region="content"
120
120
  style={{ padding: 'var(--space-xl) var(--space-m)', width: '100vw', maxWidth: '500px' }}
121
121
  title={`🎉 ${t('workspaces.select.emptyTitle')} 🎉`}
122
122
  text={t('workspaces.select.emptyText')}
@@ -13,7 +13,7 @@ export const metadata = {
13
13
  export const WorkspaceSettingsPage = () => {
14
14
  return (
15
15
  <View layout="off-center-m" style={{ height: '100%' }}>
16
- <View slot="content" surface="primary" roundness="m" inset="m">
16
+ <View data-region="content" surface="primary" roundness="m" inset="m">
17
17
  <GeneralSettings />
18
18
  </View>
19
19
  </View>
@@ -4,7 +4,7 @@ import { UserSchema } from '@ossy/users/server'
4
4
  import { Workspace, WorkspacesEvents } from '@ossy/workspaces/server'
5
5
  import { User, UsersEvents } from '@ossy/users/server'
6
6
  import { Token, TokenEvents } from '@ossy/tokens/server'
7
- import { ConfigService } from '@ossy/platform'
7
+ import { ConfigService } from '@ossy/config'
8
8
  import { createLogger } from '@ossy/observability'
9
9
 
10
10
  export const metadata = { id: '@ossy/workspaces/tasks/accept-invitation' }
@@ -1,6 +1,6 @@
1
1
  import { Aggregate } from '@ossy/event-store'
2
2
  import { Workspace, WorkspacesEvents } from '@ossy/workspaces/server'
3
- import { ConfigService } from '@ossy/platform'
3
+ import { ConfigService } from '@ossy/config'
4
4
 
5
5
  export const metadata = { id: '@ossy/workspaces/tasks/create' }
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { Aggregate } from '@ossy/event-store'
2
2
  import { Workspace } from '@ossy/workspaces/server'
3
- import { getSystemSchemas } from '@ossy/platform'
3
+ import { getSystemSchemas } from '@ossy/schema'
4
4
  import { mergeWorkspaceSchemas } from './merge-workspace-schemas.js'
5
5
 
6
6
  export const metadata = { id: '@ossy/workspaces/tasks/get-schemas' }
@@ -1,6 +1,6 @@
1
1
  import { Aggregate } from '@ossy/event-store'
2
2
  import { Workspace, WorkspacesEvents } from '@ossy/workspaces/server'
3
- import { validateSchemasForImport } from '@ossy/platform'
3
+ import { validateSchemasForImport } from '@ossy/schema'
4
4
 
5
5
  export const metadata = { id: '@ossy/workspaces/tasks/import-schemas' }
6
6
 
@@ -4,7 +4,7 @@ import { UserSchema } from '@ossy/users/server'
4
4
  import { Workspace, WorkspacesEvents } from '@ossy/workspaces/server'
5
5
  import { Token, TokenEvents } from '@ossy/tokens/server'
6
6
  import { EmailRenderer } from '@ossy/email'
7
- import { ConfigService } from '@ossy/platform'
7
+ import { ConfigService } from '@ossy/config'
8
8
  import { createLogger } from '@ossy/observability'
9
9
  import WorkspaceInvitationEmail, { subject as workspaceInvitationSubject } from './workspace-invitation.email.jsx'
10
10
 
@@ -1,46 +0,0 @@
1
- import {
2
- ActionService,
3
- mergeUserAppSettingsCookie,
4
- setAuthCookie,
5
- } from '@ossy/platform'
6
-
7
- export const metadata = {
8
- id: 'users.accept-invitation',
9
- path: '/api/v0/users/accept-invitation',
10
- action: '@ossy/workspaces/actions/accept-invitation',
11
- method: 'GET',
12
- query: ['token', 'workspaceId', 'redirect'],
13
- }
14
-
15
- export default async function handle (req, res) {
16
- if (req.method !== 'GET') {
17
- res.setHeader('Allow', 'GET')
18
- res.status(405).json({ error: 'Method Not Allowed' })
19
- return
20
- }
21
-
22
- try {
23
- const { authToken, workspaceId } = await ActionService.invoke('@ossy/workspaces/actions/accept-invitation', {
24
- payload: {
25
- token: req.query.token,
26
- workspaceId: req.query.workspaceId,
27
- },
28
- req,
29
- })
30
-
31
- setAuthCookie(res, authToken)
32
- if (workspaceId) {
33
- mergeUserAppSettingsCookie(req, res, { workspaceId })
34
- }
35
-
36
- const redirect = req.query.redirect
37
- if (redirect && typeof redirect === 'string') {
38
- res.redirect(302, redirect)
39
- return
40
- }
41
-
42
- res.status(200).json('')
43
- } catch (err) {
44
- res.status(err.status || 401).json('')
45
- }
46
- }
@@ -1,50 +0,0 @@
1
- import {
2
- ActionService,
3
- mergeUserAppSettingsCookie,
4
- } from '@ossy/platform'
5
-
6
- export const metadata = {
7
- id: 'users.select-workspace',
8
- path: '/api/v0/users/select-workspace',
9
- method: 'GET',
10
- query: ['workspaceId', 'redirect'],
11
- }
12
-
13
- export default async function handle (req, res) {
14
- if (req.method !== 'GET') {
15
- res.setHeader('Allow', 'GET')
16
- res.status(405).json({ error: 'Method Not Allowed' })
17
- return
18
- }
19
-
20
- if (!req.userId || req.userId === 'anonymous') {
21
- res.status(401).json({ error: 'Unauthorized' })
22
- return
23
- }
24
-
25
- const workspaceId = req.query.workspaceId
26
- if (!workspaceId || typeof workspaceId !== 'string') {
27
- res.status(400).json({ message: 'No workspaceId provided' })
28
- return
29
- }
30
-
31
- try {
32
- const workspaces = await ActionService.invoke('@ossy/workspaces/actions/list', { req })
33
- if (!workspaces.some((w) => w.id === workspaceId)) {
34
- res.status(403).json({ message: 'Forbidden' })
35
- return
36
- }
37
-
38
- mergeUserAppSettingsCookie(req, res, { workspaceId })
39
-
40
- const redirect = req.query.redirect
41
- if (redirect && typeof redirect === 'string') {
42
- res.redirect(302, redirect)
43
- return
44
- }
45
-
46
- res.status(200).json('')
47
- } catch (err) {
48
- res.status(err.status || 500).json({ message: err.message || 'Internal Server Error' })
49
- }
50
- }
@@ -1,35 +0,0 @@
1
- import React from 'react'
2
- import { View } from '@ossy/design-system'
3
- import { Users } from '../Users.jsx'
4
- import { withMockRouter, withMockSdk } from './decorators.jsx'
5
-
6
- export default {
7
- title: 'Workspaces/Pages/Users',
8
- component: Users,
9
- decorators: [withMockRouter, withMockSdk],
10
- parameters: {
11
- layout: 'padded',
12
- docs: {
13
- story: {
14
- inline: true,
15
- height: 'auto',
16
- },
17
- },
18
- },
19
- }
20
-
21
- export const Default = () => (
22
- <View style={{ maxWidth: 720, width: '100%' }}>
23
- <Users />
24
- </View>
25
- )
26
-
27
- export const Empty = () => (
28
- <View style={{ maxWidth: 720, width: '100%' }}>
29
- <Users />
30
- </View>
31
- )
32
-
33
- Empty.parameters = {
34
- mockSdk: { users: [] },
35
- }
@@ -1,59 +0,0 @@
1
- import {
2
- createMockRouterDecorator,
3
- createMockSdkDecorator,
4
- } from '../../../../.storybook/decorators/index.jsx'
5
-
6
- export const sampleWorkspaceUsers = [
7
- { id: 'user-1', firstName: 'Anna', lastName: 'Svensson', email: 'anna@example.com', type: 'User' },
8
- { id: 'user-2', firstName: 'Erik', lastName: 'Lind', email: 'erik@example.com', type: 'User' },
9
- { id: 'bot-1', firstName: 'Deploy', lastName: 'Bot', email: 'bot@example.com', type: 'Bot' },
10
- ]
11
-
12
- export const sampleWorkspaces = [
13
- { id: 'ws-demo-1', name: 'Demo Workspace' },
14
- { id: 'ws-demo-2', name: 'Acme Corp' },
15
- ]
16
-
17
- export const sampleCurrentUser = {
18
- id: 'user-1',
19
- firstName: 'Anna',
20
- lastName: 'Svensson',
21
- email: 'anna@example.com',
22
- }
23
-
24
- function createWorkspaceHandlers (overrides = {}) {
25
- const users = 'users' in overrides ? overrides.users : sampleWorkspaceUsers
26
- const workspaces = 'workspaces' in overrides ? overrides.workspaces : sampleWorkspaces
27
- const currentUser = 'currentUser' in overrides ? overrides.currentUser : sampleCurrentUser
28
-
29
- return {
30
- '@ossy/workspaces/actions/get-users': async () => users,
31
- '@ossy/workspaces/actions/list': async () => workspaces,
32
- '@ossy/authentication/actions/get-current-user': async () => currentUser,
33
- }
34
- }
35
-
36
- const defaultMockRouter = {
37
- href: 'http://localhost/en/workspaces',
38
- pages: [],
39
- language: 'en',
40
- defaultLanguage: 'en',
41
- supportedLanguages: ['en', 'sv'],
42
- params: {},
43
- searchParams: {},
44
- navigate: () => {},
45
- getHref: (target) => {
46
- const id = typeof target === 'string' ? target : target?.id
47
- if (id === '@workspace/invitations/add') return '/en/invitations/add'
48
- if (id === '@profile/workspaces/create') return '/en/profile/workspaces/create'
49
- if (id === '@home/home') return '/en/home'
50
- if (id === '@storage/home' && target?.params?.workspaceId) {
51
- return `/en/storage/${target.params.workspaceId}`
52
- }
53
- return `/en/${String(id ?? '').replace(/\//g, '-')}`
54
- },
55
- back: () => {},
56
- }
57
-
58
- export const withMockSdk = createMockSdkDecorator(createWorkspaceHandlers)
59
- export const withMockRouter = createMockRouterDecorator(defaultMockRouter)