@ossy/workspaces 1.16.7 → 1.17.1

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.
Files changed (53) hide show
  1. package/README.md +1 -0
  2. package/package.json +5 -4
  3. package/src/AuthenticationGuard.jsx +23 -10
  4. package/src/CreateWorkspacePage.jsx +18 -12
  5. package/src/Definition.js +1 -17
  6. package/src/GeneralSettings.jsx +27 -70
  7. package/src/Invitations.jsx +11 -19
  8. package/src/Invite.jsx +17 -14
  9. package/src/SelectWorkspacePage.jsx +17 -22
  10. package/src/Users.jsx +10 -15
  11. package/src/accept-invitation.action.js +1 -85
  12. package/src/accept-invitation.task.js +84 -0
  13. package/src/create-api-token.action.js +1 -17
  14. package/src/create-api-token.task.js +16 -0
  15. package/src/create.action.js +1 -30
  16. package/src/create.task.js +29 -0
  17. package/src/disable-service.action.js +1 -28
  18. package/src/disable-service.task.js +27 -0
  19. package/src/en.translations.json +72 -0
  20. package/src/enable-service.action.js +1 -28
  21. package/src/enable-service.task.js +27 -0
  22. package/src/get-api-tokens.action.js +1 -11
  23. package/src/get-api-tokens.task.js +10 -0
  24. package/src/get-invitations.action.js +1 -11
  25. package/src/get-invitations.task.js +10 -0
  26. package/src/get-resource-templates.action.js +1 -19
  27. package/src/get-resource-templates.task.js +18 -0
  28. package/src/get-users.action.js +1 -14
  29. package/src/get-users.task.js +13 -0
  30. package/src/get.action.js +1 -14
  31. package/src/get.task.js +13 -0
  32. package/src/import-resource-templates.action.js +1 -27
  33. package/src/import-resource-templates.task.js +26 -0
  34. package/src/index.js +14 -2
  35. package/src/invite-user.action.js +1 -85
  36. package/src/invite-user.task.js +84 -0
  37. package/src/list.action.js +1 -9
  38. package/src/list.task.js +8 -0
  39. package/src/remove-member.action.js +1 -17
  40. package/src/remove-member.task.js +16 -0
  41. package/src/server.js +3 -0
  42. package/src/sv.translations.json +72 -0
  43. package/src/sync-workspace-membership.task.js +4 -3
  44. package/src/workspaces.spec.js +71 -80
  45. package/src/current.api.js +0 -30
  46. package/src/invitations.api.js +0 -46
  47. package/src/item.api.js +0 -32
  48. package/src/list.api.js +0 -35
  49. package/src/members.api.js +0 -42
  50. package/src/resource-templates.api.js +0 -35
  51. package/src/services-disable.api.js +0 -23
  52. package/src/services-enable.api.js +0 -23
  53. package/src/tokens.api.js +0 -35
package/README.md CHANGED
@@ -26,6 +26,7 @@ Workspaces **feature package** for the Ossy platform — provides workspace crea
26
26
  | `AuthenticationGuard` | Wraps children, shows error for unauthenticated users |
27
27
  | `patchUserWorkspaceId` | Utility to update the active workspace cookie |
28
28
  | `Definition` | Feature metadata (id, actions, views) |
29
+ | `ListWorkspaces`, `GetWorkspace`, … | Platform action POJOs — use with `useSdk().read()` / `invoke()` |
29
30
 
30
31
  ## Usage
31
32
 
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@ossy/workspaces",
3
- "description": "Workspaces feature package create, select, and manage workspaces, users, and invitations",
4
- "version": "1.16.7",
3
+ "description": "Workspaces feature package - create, select, and manage workspaces, users, and invitations",
4
+ "version": "1.17.1",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
7
7
  "module": "./src/index.js",
8
8
  "exports": {
9
9
  ".": "./src/index.js",
10
+ "./server": "./src/server.js",
10
11
  "./workspace-invitation.email.jsx": "./src/workspace-invitation.email.jsx"
11
12
  },
12
13
  "scripts": {
@@ -25,7 +26,7 @@
25
26
  },
26
27
  "devDependencies": {
27
28
  "@jest/globals": "^30.2.0",
28
- "@ossy/platform": "^1.38.7",
29
+ "@ossy/platform": "^1.39.1",
29
30
  "casual": "^1.6.2",
30
31
  "jest": "^30.2.0"
31
32
  },
@@ -37,5 +38,5 @@
37
38
  "/src",
38
39
  "README.md"
39
40
  ],
40
- "gitHead": "f65df0cd6da864c314c4f424112e05e8e2dec0ff"
41
+ "gitHead": "c0ba5d90749690634e4dc2705178ff8d89dd3070"
41
42
  }
@@ -1,20 +1,33 @@
1
- import React from 'react'
2
- import { AuthenticationStatus, useAuthentication } from '@ossy/sdk-react'
3
- import { Switch, View, Guide, Icon } from '@ossy/design-system'
1
+ import React, { useMemo } from 'react'
2
+ import { AuthenticationStatus, GetCurrentUser } from '@ossy/authentication'
3
+ import { useSdk, AsyncStatus } from '@ossy/sdk-react'
4
+ import { Switch, View, Guide, Icon, useLocale } from '@ossy/design-system'
4
5
 
5
6
  export const AuthenticationGuard = ({ children }) => {
6
- const { status } = useAuthentication()
7
+ const { t } = useLocale()
8
+ const sdk = useSdk()
9
+ const { status, data: user } = sdk.read(GetCurrentUser)
10
+
11
+ const authStatus = useMemo(() => {
12
+ if (status === AsyncStatus.Loading || status === AsyncStatus.NotInitialized) {
13
+ return AuthenticationStatus.Verifying
14
+ }
15
+ if (status === AsyncStatus.Success && user) {
16
+ return AuthenticationStatus.Authenticated
17
+ }
18
+ return AuthenticationStatus.NotAuthenticated
19
+ }, [status, user])
7
20
 
8
21
  return (
9
- <Switch on={status}>
22
+ <Switch on={authStatus}>
10
23
 
11
24
  <Switch.Case match={[AuthenticationStatus.NotAuthenticated]}>
12
25
  <View layout="off-center" style={{ height: '100%' }}>
13
26
  <Guide
14
27
  style={{ width: '100vw', maxWidth: '300px' }}
15
28
  slot="content"
16
- title="Not Authenticated"
17
- text="You need to login to view this page"
29
+ title={t('authentication.guard.notAuthenticated.title')}
30
+ text={t('authentication.guard.notAuthenticated.text')}
18
31
  />
19
32
  </View>
20
33
  </Switch.Case>
@@ -24,13 +37,13 @@ export const AuthenticationGuard = ({ children }) => {
24
37
  <Guide
25
38
  style={{ width: '100vw', maxWidth: '300px' }}
26
39
  slot="content"
27
- title="Error"
28
- text="An error occurred while trying to authenticate, try again in a few minutes"
40
+ title={t('authentication.guard.error.title')}
41
+ text={t('authentication.guard.error.text')}
29
42
  />
30
43
  </View>
31
44
  </Switch.Case>
32
45
 
33
- <Switch.Case match={[AuthenticationStatus.Verifying, AuthenticationStatus.NoInitialized]}>
46
+ <Switch.Case match={[AuthenticationStatus.Verifying, AuthenticationStatus.NotInitialized]}>
34
47
  <View layout="off-center" style={{ height: '100%' }}>
35
48
  <Icon
36
49
  name="spinner"
@@ -1,32 +1,37 @@
1
1
  import React, { useState } from 'react'
2
- import { useWorkspaces } from '@ossy/sdk-react'
2
+ import { ListWorkspaces, CreateWorkspace } from '@ossy/workspaces'
3
+ import { useSdk, cacheKey } from '@ossy/sdk-react'
3
4
  import {
4
5
  Button,
5
6
  useInputValue,
6
7
  Title,
7
8
  Input,
8
- View
9
+ View,
10
+ useLocale,
9
11
  } from '@ossy/design-system'
10
12
  import { useRouter } from '@ossy/router-react'
11
13
  import { AuthenticationGuard } from './AuthenticationGuard.jsx'
12
14
  import { patchUserWorkspaceId } from './patchUserWorkspaceId.js'
15
+ import { metadata as CreateWorkspaceMeta } from './create.action.js'
13
16
 
14
17
  export const CreateWorkspacePage = () => {
15
18
  const router = useRouter()
19
+ const { t } = useLocale()
16
20
  const [error, setError] = useState()
17
21
  const [workspaceName, setWorkspaceName] = useInputValue()
18
- const { createWorkspace } = useWorkspaces()
22
+ const sdk = useSdk()
19
23
 
20
24
  const onCreateWorkspace = workspaceName => {
21
- createWorkspace(workspaceName)
22
- .then((workspace) =>
23
- patchUserWorkspaceId(workspace.id).then((res) => {
25
+ sdk.invoke(CreateWorkspace, { name: workspaceName })
26
+ .then((workspace) => {
27
+ sdk.invalidate(cacheKey(ListWorkspaces))
28
+ return patchUserWorkspaceId(workspace.id).then((res) => {
24
29
  if (!res.ok) throw new Error('Could not select the new workspace')
25
30
  window.location.assign(
26
31
  router.getHref({ id: '@storage/home', params: { workspaceId: workspace.id } })
27
32
  )
28
33
  })
29
- )
34
+ })
30
35
  .catch(err => { setError(err.message) })
31
36
  }
32
37
 
@@ -34,14 +39,14 @@ export const CreateWorkspacePage = () => {
34
39
  <AuthenticationGuard>
35
40
  <View gap="m">
36
41
 
37
- <title>Create workspace</title>
38
- <Title variant="primary" className="stack-m">Create a new workspace</Title>
42
+ <title>{t('profile/workspaces/create.documentTitle')}</title>
43
+ <Title variant="primary" className="stack-m">{t('workspaces.create.title')}</Title>
39
44
 
40
45
  <Input
41
46
  id="workspaceName"
42
47
  className={error ? 'stack-s' : 'stack-m'}
43
48
  type="text"
44
- placeholder="Workspace name"
49
+ placeholder={t('workspaces.create.namePlaceholder')}
45
50
  required
46
51
  onChange={setWorkspaceName}
47
52
  style={{ width: '100%' }}
@@ -54,13 +59,14 @@ export const CreateWorkspacePage = () => {
54
59
  <Button
55
60
  variant="link"
56
61
  id="cancel"
57
- href={() => router.back()}>Cancel
62
+ href={() => router.back()}>{t('workspaces.create.cancel')}
58
63
  </Button>
59
64
 
60
65
  <Button
61
66
  id="createWorkspace"
67
+ data-action={CreateWorkspaceMeta.id}
62
68
  variant="cta"
63
- onClick={() => onCreateWorkspace(workspaceName)}>Create
69
+ onClick={() => onCreateWorkspace(workspaceName)}>{t('workspaces.create.submit')}
64
70
  </Button>
65
71
 
66
72
  </View>
package/src/Definition.js CHANGED
@@ -2,22 +2,6 @@ export const Definition = {
2
2
  id: 'workspaces',
3
3
  title: 'Workspaces',
4
4
  description: 'Workspace lifecycle, members, invitations, and services.',
5
- module: {
6
- id: 'workspaces',
7
- enabled: true
8
- },
5
+ icon: 'users',
9
6
  statuses: ['beta'],
10
- actions: [
11
- 'workspaces.create',
12
- 'workspaces.invite-user',
13
- 'workspaces.enable-service',
14
- 'workspaces.disable-service'
15
- ],
16
- views: [
17
- 'workspaces.get-all',
18
- 'workspaces.get',
19
- 'workspaces.get-current',
20
- 'workspaces.get-users'
21
- ],
22
- tasks: []
23
7
  }
@@ -1,87 +1,44 @@
1
1
  import React, { useState } from 'react'
2
- import { useWorkspace, useUser, AsyncStatus } from '@ossy/sdk-react'
3
- import { Switch, Title, Button, View, Text } from '@ossy/design-system'
2
+ import { GetWorkspace } from '@ossy/workspaces'
3
+ import { GetCurrentUser } from '@ossy/authentication'
4
+ import { useSdk, AsyncStatus } from '@ossy/sdk-react'
5
+ import { Switch, Title, Button, View, Text, useLocale } from '@ossy/design-system'
4
6
 
5
- const formatDate = (timestamp) => {
6
- if (!timestamp) return ''
7
- const date = new Date(timestamp)
8
- return date.toLocaleDateString()
9
- }
10
-
11
- const FlowStage = {
12
- View: 'View',
13
- Edit: 'Edit'
14
- }
15
-
16
- const availableServices = [
17
- '@ossy/jobs/visual-content-descriptors',
18
- '@ossy/jobs/resize-common-web',
19
- '@ossy/resumes',
20
- '@ossy/consultancy',
21
- '@ossy/apps',
22
- '@ossy/domains',
23
- ]
7
+ const formatDate = (timestamp) => timestamp ? new Date(timestamp).toLocaleDateString() : ''
8
+ const FlowStage = { View: 'View', Edit: 'Edit' }
24
9
 
25
10
  export const GeneralSettings = () => {
26
- const { workspace } = useWorkspace()
27
- const { status: userStatus, user } = useUser()
11
+ const { t } = useLocale()
12
+ const sdk = useSdk()
13
+ const { data: workspace } = sdk.read(GetWorkspace)
14
+ const { status: userStatus } = sdk.read(GetCurrentUser)
28
15
  const [flowStage, setFlowStage] = useState(FlowStage.View)
29
-
30
16
  const services = workspace?.services || {}
31
17
 
32
- const isWorkspaceCreator =
33
- userStatus === AsyncStatus.Success &&
34
- Boolean(workspace?.createdBy) &&
35
- Boolean(user?.id) &&
36
- workspace.createdBy === user.id
37
-
38
18
  return (
39
19
  <View gap="l" inset="m">
40
20
  <View layout="row" gap="s" justifyContent="space-between">
41
- <Title>Workspace details</Title>
42
-
43
- <View>
44
- <Switch on={flowStage}>
45
- <Switch.Case match={[FlowStage.View]}>
46
- <Button prefix={{ size: 's', name: 'pen' }} variant="cta" disabled>
47
- Edit
48
- </Button>
49
- </Switch.Case>
50
- </Switch>
51
- </View>
21
+ <Title>{t('workspace.settings.detailsTitle')}</Title>
22
+ <Switch on={flowStage}>
23
+ <Switch.Case match={[FlowStage.View]}>
24
+ <Button prefix={{ size: 's', name: 'pen' }} variant="cta" disabled>{t('workspace.settings.edit')}</Button>
25
+ </Switch.Case>
26
+ </Switch>
52
27
  </View>
53
-
54
- <View gap="s" style={{ height: '100%' }}>
55
- <View layout="row" gap="s">
56
- <Text style={{ fontWeight: 'bold' }}>Id:</Text>
57
- <Text>{workspace.id}</Text>
58
- </View>
59
- <View layout="row" gap="s">
60
- <Text style={{ fontWeight: 'bold' }}>Name:</Text>
61
- <Text>{workspace.name}</Text>
62
- </View>
63
- <View layout="row" gap="s">
64
- <Text style={{ fontWeight: 'bold' }}>Created:</Text>
65
- <Text>{formatDate(workspace?.created)}</Text>
66
- </View>
67
- </View>
68
-
69
- {isWorkspaceCreator && (
28
+ {userStatus === AsyncStatus.Loading ? (
29
+ <Text>{t('workspace.settings.loading')}</Text>
30
+ ) : (
70
31
  <View gap="s">
71
- <Title variant="secondary">Workspace services</Title>
72
- <Text variant="small" style={{ maxWidth: '42rem' }}>
73
- Turn features on or off for this workspace.
74
- </Text>
75
- {availableServices.map((x) => (
76
- <View key={x}>
77
- <Text>
78
- {x} : {services[x] !== false ? 'On' : 'Off'}
79
- </Text>
80
- </View>
81
- ))}
32
+ <View layout="row" gap="s"><Text style={{ fontWeight: 'bold' }}>{t('workspace.settings.name')}</Text><Text>{workspace?.name}</Text></View>
33
+ <View layout="row" gap="s"><Text style={{ fontWeight: 'bold' }}>{t('workspace.settings.created')}</Text><Text>{formatDate(workspace?.created)}</Text></View>
34
+ <Title variant="tertiary">{t('workspace.settings.services')}</Title>
35
+ <View gap="xs">
36
+ {Object.entries(services).map(([key, enabled]) => (
37
+ <Text key={key}>{key}: {enabled ? 'on' : 'off'}</Text>
38
+ ))}
39
+ </View>
82
40
  </View>
83
41
  )}
84
-
85
42
  </View>
86
43
  )
87
44
  }
@@ -1,44 +1,36 @@
1
1
  import React from 'react'
2
- import { useWorkspace } from '@ossy/sdk-react'
3
- import { Title, Text, Button, View, Icon } from '@ossy/design-system'
2
+ import { GetWorkspace } from '@ossy/workspaces'
3
+ import { useSdk } from '@ossy/sdk-react'
4
+ import { Title, Text, Button, View, Icon, useLocale } from '@ossy/design-system'
4
5
  import { useRouter } from '@ossy/router-react'
5
6
 
6
7
  export const Invitations = () => {
8
+ const { t } = useLocale()
7
9
  const router = useRouter()
8
- const { workspace } = useWorkspace()
10
+ const sdk = useSdk()
11
+ const { data: workspace } = sdk.read(GetWorkspace)
9
12
  const invitations = workspace?.invitations || []
10
13
 
11
14
  return (
12
15
  <View gap="m">
13
-
14
16
  <View inset="s" gap="s">
15
-
16
17
  <View layout="row" justifyContent="space-between" alignItems="center">
17
- <Title>Invitations</Title>
18
+ <Title>{t('workspace.invitations.title')}</Title>
18
19
  <Button variant="cta" href={router.getHref('@workspace/invitations/add')} prefix="user-add">
19
- Invite user
20
+ {t('workspace.invitations.invite')}
20
21
  </Button>
21
22
  </View>
22
-
23
- <Text style={{ maxWidth: '400px' }}>
24
- Invite users to your workspace to collaborate.
25
- </Text>
26
-
23
+ <Text style={{ maxWidth: '400px' }}>{t('workspace.invitations.description')}</Text>
27
24
  </View>
28
-
29
25
  <View gap="xs">
30
26
  {invitations.map(invite => (
31
27
  <View layout="row" roundness="s" alignItems="center" inset="m" gap="m" selectable key={invite.email}>
32
28
  <Icon name="mail" />
33
- <View>
34
- <Text variant="small" as="span">{invite.email}</Text>
35
- </View>
29
+ <View><Text variant="small" as="span">{invite.email}</Text></View>
36
30
  </View>
37
31
  ))}
38
32
  </View>
39
-
40
- {invitations.length === 0 && <Text>No invitations</Text>}
41
-
33
+ {invitations.length === 0 && <Text>{t('workspace.invitations.empty')}</Text>}
42
34
  </View>
43
35
  )
44
36
  }
package/src/Invite.jsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import React, { useState, useRef } from 'react'
2
- import { useWorkspace } from '@ossy/sdk-react'
2
+ import { InviteUser } from '@ossy/workspaces'
3
+ import { useSdk } from '@ossy/sdk-react'
3
4
  import { useRouter } from '@ossy/router-react'
4
5
  import {
5
6
  useInputValue,
@@ -9,7 +10,8 @@ import {
9
10
  Switch,
10
11
  Guide,
11
12
  Text,
12
- View
13
+ View,
14
+ useLocale,
13
15
  } from '@ossy/design-system'
14
16
 
15
17
  const FlowStage = {
@@ -19,15 +21,16 @@ const FlowStage = {
19
21
  }
20
22
 
21
23
  export const Invite = () => {
24
+ const { t } = useLocale()
22
25
  const router = useRouter()
23
- const { inviteUser } = useWorkspace()
26
+ const sdk = useSdk()
24
27
  const [flowStage, setFlowStage] = useState(FlowStage.EnterEmail)
25
28
  const [email, setEmail] = useInputValue('')
26
29
  const formRef = useRef()
27
30
 
28
31
  const sendInvite = event => {
29
32
  event.preventDefault()
30
- formRef.current.reportValidity() && inviteUser(email)
33
+ formRef.current.reportValidity() && sdk.invoke(InviteUser, { email })
31
34
  .then(() => setFlowStage(FlowStage.Success))
32
35
  .catch(() => setFlowStage(FlowStage.Error))
33
36
  }
@@ -35,13 +38,13 @@ export const Invite = () => {
35
38
  return (
36
39
  <Switch on={flowStage}>
37
40
 
38
- <title>Invite user</title>
41
+ <title>{t('workspace/invitations/add.documentTitle')}</title>
39
42
 
40
43
  <Switch.Case match={[FlowStage.EnterEmail]}>
41
44
  <View gap="m">
42
- <Title variant="primary">Invite user</Title>
45
+ <Title variant="primary">{t('workspace.invite.title')}</Title>
43
46
  <Text>
44
- Invite a user to manage and contribute content to this workspace
47
+ {t('workspace.invite.description')}
45
48
  </Text>
46
49
  <form
47
50
  ref={formRef}
@@ -54,7 +57,7 @@ export const Invite = () => {
54
57
  id="registerField"
55
58
  className="stack-m"
56
59
  type="email"
57
- placeholder="Email address"
60
+ placeholder={t('workspace.invite.emailPlaceholder')}
58
61
  required
59
62
  value={email}
60
63
  onChange={e => setEmail(e.target.value)}
@@ -65,14 +68,15 @@ export const Invite = () => {
65
68
  <Button
66
69
  variant="link"
67
70
  id="cancelButton"
68
- href={() => router.back()}>Cancel
71
+ href={() => router.back()}>{t('design-system.cancel')}
69
72
  </Button>
70
73
 
71
74
  <Button
72
75
  variant="cta"
73
76
  id="registerButton"
77
+ data-action={InviteUser.id}
74
78
  type="submit"
75
- onClick={sendInvite}>Send invite
79
+ onClick={sendInvite}>{t('workspace.invite.submit')}
76
80
  </Button>
77
81
  </View>
78
82
  </View>
@@ -82,12 +86,11 @@ export const Invite = () => {
82
86
 
83
87
  <Switch.Case match={[FlowStage.Success]}>
84
88
  <Guide
85
- title="Success"
89
+ title={t('workspace.invite.successTitle')}
86
90
  titleVariant="primary"
87
91
  >
88
92
  <Text>
89
- We sent them an invitation over email.
90
- When they have accepted they will show up in the list of users.
93
+ {t('workspace.invite.successBody')}
91
94
  <br/>
92
95
  ✌️
93
96
  </Text>
@@ -96,7 +99,7 @@ export const Invite = () => {
96
99
 
97
100
  <Switch.Case match={[FlowStage.Error]}>
98
101
  <Text>
99
- Something went wrong, try again in a couple of minutes
102
+ {t('workspace.invite.error')}
100
103
  </Text>
101
104
  </Switch.Case>
102
105
 
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
- import { useWorkspaces, AsyncStatus } from '@ossy/sdk-react'
3
- import { Title, Text, Switch, Button, View, Guide, Icon } from '@ossy/design-system'
2
+ import { ListWorkspaces } from '@ossy/workspaces'
3
+ import { useSdk, AsyncStatus } from '@ossy/sdk-react'
4
+ import { Title, Text, Switch, Button, View, Guide, Icon, useLocale } from '@ossy/design-system'
4
5
  import { useRouter } from '@ossy/router-react'
5
6
  import { AuthenticationGuard } from './AuthenticationGuard.jsx'
6
7
  import { patchUserWorkspaceId } from './patchUserWorkspaceId.js'
@@ -14,7 +15,9 @@ const PageFlow = {
14
15
 
15
16
  export const SelectWorkspacePage = () => {
16
17
  const router = useRouter()
17
- const { status: asyncStatus, workspaces } = useWorkspaces()
18
+ const { t } = useLocale()
19
+ const sdk = useSdk()
20
+ const { status: asyncStatus, data: workspaces = [] } = sdk.read(ListWorkspaces)
18
21
 
19
22
  const pageFlow = (asyncStatus === AsyncStatus.Success && workspaces.length === 0)
20
23
  ? PageFlow.NoWorkspacesCreated
@@ -30,7 +33,7 @@ export const SelectWorkspacePage = () => {
30
33
  return (
31
34
  <AuthenticationGuard>
32
35
 
33
- <title>Select workspace</title>
36
+ <title>{t('profile/workspaces.documentTitle')}</title>
34
37
 
35
38
  <Switch on={pageFlow}>
36
39
  <Switch.Case match={[PageFlow.Success]}>
@@ -41,14 +44,14 @@ export const SelectWorkspacePage = () => {
41
44
  marginBottom: 'var(--space-m)',
42
45
  }}>
43
46
  <Title variant="primary">
44
- My workspaces
47
+ {t('workspaces.select.title')}
45
48
  </Title>
46
49
  <Button
47
50
  prefix="math-plus"
48
51
  variant="cta"
49
52
  href={router.getHref('@profile/workspaces/create')}
50
53
  className="mobile:d-none">
51
- New workspace
54
+ {t('workspaces.select.newWorkspace')}
52
55
  </Button>
53
56
  </div>
54
57
  </Switch.Case>
@@ -61,16 +64,12 @@ export const SelectWorkspacePage = () => {
61
64
  <Guide
62
65
  slot="content"
63
66
  style={{ width: '100vw', maxWidth: '500px' }}
64
- title="We could not load your workspaces"
65
- text={`
66
- Something went wrong when loading your workspaces.
67
- Maybe your session have expired, or we messed up somehow.
68
- Try starting over from our home page.
69
- `}
67
+ title={t('workspaces.select.errorTitle')}
68
+ text={t('workspaces.select.errorText')}
70
69
  actions={[{
71
70
  variant: 'cta',
72
71
  href: '/',
73
- label: 'Go to our home page'
72
+ label: t('workspaces.select.errorAction')
74
73
  }]}
75
74
  />
76
75
  </View>
@@ -83,14 +82,14 @@ export const SelectWorkspacePage = () => {
83
82
  style={{ width: '64px', height: '64px' }}
84
83
  className="rotate"
85
84
  />
86
- <Text>Loading...</Text>
85
+ <Text>{t('workspaces.select.loading')}</Text>
87
86
  </Switch.Case>
88
87
 
89
88
  <Switch.Case match={[PageFlow.Success]}>
90
89
  <View gap="m">
91
90
 
92
91
  <Text style={{ maxWidth: '400px' }}>
93
- Workspaces are separate environments where you can manage resources, templates, services and billing.
92
+ {t('workspaces.select.description')}
94
93
  </Text>
95
94
 
96
95
  <View stack gap="xs" style={{ overflowY: 'auto' }}>
@@ -122,15 +121,11 @@ export const SelectWorkspacePage = () => {
122
121
  <Guide
123
122
  slot="content"
124
123
  style={{ padding: 'var(--space-xl) var(--space-m)', width: '100vw', maxWidth: '500px' }}
125
- title="🎉 Let's get the party started 🎉"
126
- text={`
127
- To get started we need to create a workspace.
128
- A workspace is an encapsulation of resources, resource templates,
129
- billing information, and what users have access to these things.
130
- `}
124
+ title={`🎉 ${t('workspaces.select.emptyTitle')} 🎉`}
125
+ text={t('workspaces.select.emptyText')}
131
126
  actions={[{
132
127
  variant: 'cta',
133
- label: 'Create a workspace',
128
+ label: t('workspaces.select.emptyAction'),
134
129
  href: router.getHref('@profile/workspaces/create')
135
130
  }]}
136
131
  />
package/src/Users.jsx CHANGED
@@ -1,32 +1,28 @@
1
1
  import React from 'react'
2
- import { useUsers, AsyncStatus } from '@ossy/sdk-react'
3
- import { Text, View, Icon, Title, Button } from '@ossy/design-system'
2
+ import { GetUsers } from '@ossy/workspaces'
3
+ import { useSdk, AsyncStatus } from '@ossy/sdk-react'
4
+ import { Text, View, Icon, Title, Button, useLocale } from '@ossy/design-system'
4
5
  import { useRouter } from '@ossy/router-react'
5
6
 
6
7
  export const Users = () => {
8
+ const { t } = useLocale()
7
9
  const router = useRouter()
8
- const { users = [], status } = useUsers()
10
+ const sdk = useSdk()
11
+ const { status, data: users = [] } = sdk.read(GetUsers)
9
12
 
10
- if (status === AsyncStatus.Loading) return <>Loading</>
13
+ if (status === AsyncStatus.Loading) return <>{t('workspace.users.loading')}</>
11
14
 
12
15
  return (
13
16
  <View gap="m">
14
-
15
17
  <View inset="s" gap="s">
16
-
17
18
  <View layout="row" justifyContent="space-between" alignItems="center">
18
- <Title>Users</Title>
19
+ <Title>{t('workspace.users.title')}</Title>
19
20
  <Button variant="cta" href={router.getHref('@workspace/invitations/add')} prefix="user-add">
20
- Invite user
21
+ {t('workspace.users.invite')}
21
22
  </Button>
22
23
  </View>
23
-
24
- <Text style={{ maxWidth: '400px' }}>
25
- Manage users in your workspace.
26
- </Text>
27
-
24
+ <Text style={{ maxWidth: '400px' }}>{t('workspace.users.description')}</Text>
28
25
  </View>
29
-
30
26
  <View gap="xs">
31
27
  {users.map(user => (
32
28
  <View layout="row" roundness="s" alignItems="center" inset="m" gap="m" selectable key={user.id}>
@@ -41,7 +37,6 @@ export const Users = () => {
41
37
  </View>
42
38
  ))}
43
39
  </View>
44
-
45
40
  </View>
46
41
  )
47
42
  }