@mostrom/app-shell 0.1.1 → 0.1.3
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 +63 -86
- package/bun.lock +5 -3
- package/package.json +3 -9
- package/scripts/publish-npm.sh +71 -14
- package/src/AppShell.tsx +4 -6
- package/src/components/data-table/index.ts +1 -1
- package/src/components/global-header/ServicesMenu.tsx +1 -1
- package/src/components/layout/AppBreadcrumb.tsx +0 -1
- package/src/components/layout/AppLayout.tsx +1 -1
- package/src/components/layout/AppNavigation.tsx +2 -2
- package/src/components/layout/AppSidebar.tsx +1 -2
- package/src/components/sectioned-list-board/board-card-content.tsx +3 -3
- package/src/components/sectioned-list-table/README.md +1 -1
- package/src/components/sectioned-list-table/table-cell-content.tsx +1 -1
- package/src/components/ui/actions-dropdown.tsx +0 -1
- package/src/components/ui/badge.tsx +59 -0
- package/src/components/ui/button.tsx +7 -1
- package/src/components/ui/index.ts +2 -0
- package/src/components/ui/space-between.tsx +59 -0
- package/src/index.ts +1 -1
- package/src/styles.css +16 -821
- package/src/vite.js +41 -8
- package/bin/init.js +0 -269
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# App Shell
|
|
2
2
|
|
|
3
|
-
Shared
|
|
3
|
+
Shared layout shell used by all platform services. Provides a consistent layout pattern with global header, service navigation, and content areas.
|
|
4
4
|
|
|
5
5
|
## Publishing to npm
|
|
6
6
|
|
|
@@ -14,69 +14,63 @@ From `platform/shared/packages/app-shell`:
|
|
|
14
14
|
Default scope is `@mostrom` (override with `--scope` if needed).
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
# Dry run
|
|
18
|
-
npm run publish:npm:dry-run
|
|
19
|
-
# or: sh scripts/publish-npm.sh --
|
|
17
|
+
# Dry run (auto-increment patch version)
|
|
18
|
+
npm run publish:npm:dry-run
|
|
19
|
+
# or: sh scripts/publish-npm.sh --dry-run
|
|
20
20
|
|
|
21
|
-
# Publish to latest
|
|
21
|
+
# Publish to latest (auto-increment patch version)
|
|
22
|
+
npm run publish:npm
|
|
23
|
+
# or: sh scripts/publish-npm.sh
|
|
24
|
+
|
|
25
|
+
# First run or explicit override
|
|
22
26
|
npm run publish:npm -- --version 0.1.0
|
|
23
27
|
# or: sh scripts/publish-npm.sh --version 0.1.0
|
|
24
28
|
|
|
25
29
|
# Publish to custom tag
|
|
26
|
-
npm run publish:npm -- --
|
|
27
|
-
# or: sh scripts/publish-npm.sh --
|
|
30
|
+
npm run publish:npm -- --tag next
|
|
31
|
+
# or: sh scripts/publish-npm.sh --tag next
|
|
28
32
|
```
|
|
29
33
|
|
|
30
|
-
The script reads `NODE_AUTH_TOKEN` from environment variables, and also checks `app-shell/.env` for that key.
|
|
34
|
+
The script reads `NODE_AUTH_TOKEN` from environment variables, and also checks `app-shell/.env` for that key. It stores the last successful version in `scripts/.publish-version` and auto-increments patch versions on subsequent runs.
|
|
35
|
+
|
|
36
|
+
No init script is shipped in the published package.
|
|
31
37
|
|
|
32
38
|
## Quick Start
|
|
33
39
|
|
|
34
|
-
###
|
|
40
|
+
### Setup (No Init Script)
|
|
35
41
|
|
|
36
|
-
|
|
42
|
+
App setup is file-based and does not require running an init command.
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
# From your app's frontend directory, run the init script directly
|
|
40
|
-
node ../../../shared/packages/app-shell/bin/init.js
|
|
44
|
+
Install using npm aliases so existing imports stay as `@platform/*`:
|
|
41
45
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@platform/app-shell": "npm:@mostrom/app-shell@latest",
|
|
50
|
+
"@platform/service-catalog": "npm:@mostrom/service-catalog@latest"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
47
53
|
```
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
The init script creates/updates:
|
|
52
|
-
|
|
53
|
-
- `app/tailwind.css` - Imports app-shell styles
|
|
54
|
-
- `tailwind.config.ts` - Configured to scan app-shell components
|
|
55
|
-
- `components.json` - shadcn/ui configuration
|
|
56
|
-
- `app/lib/utils.ts` - Utility functions (cn, getBasePathHref)
|
|
55
|
+
Required app files:
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
| CSS changes in app-shell | No - changes are picked up automatically |
|
|
64
|
-
| Adding new shadcn components | No - use `npx shadcn@latest add <component>` |
|
|
65
|
-
| Tailwind not scanning app-shell classes | Yes, with `--force` to regenerate tailwind.config.ts |
|
|
66
|
-
| Upgrading app-shell with new required files | Yes, with `--force` |
|
|
57
|
+
- `app/tailwind.css`
|
|
58
|
+
- `tailwind.config.ts`
|
|
59
|
+
- `components.json`
|
|
60
|
+
- `app/lib/utils.ts`
|
|
61
|
+
- `vite.config.ts` using `getSharedViteConfig()` from `@platform/app-shell/vite`
|
|
67
62
|
|
|
68
63
|
### Troubleshooting
|
|
69
64
|
|
|
70
65
|
**Styles not applying from app-shell:**
|
|
71
66
|
|
|
72
|
-
1. Ensure `tailwind.config.ts` includes
|
|
67
|
+
1. Ensure `tailwind.config.ts` includes app-shell content:
|
|
73
68
|
```ts
|
|
74
69
|
content: [
|
|
75
70
|
"./app/**/*.{ts,tsx,js,jsx}",
|
|
76
|
-
"
|
|
71
|
+
"./node_modules/@platform/app-shell/src/**/*.{ts,tsx}",
|
|
77
72
|
],
|
|
78
73
|
```
|
|
79
|
-
2. Run `node ../../../shared/packages/app-shell/bin/init.js --force` to regenerate config files
|
|
80
74
|
|
|
81
75
|
**Conflicting CSS (wrong colors, broken layout):**
|
|
82
76
|
|
|
@@ -101,72 +95,55 @@ The init script creates/updates:
|
|
|
101
95
|
+--------+-----------------------------------------+---------------+
|
|
102
96
|
```
|
|
103
97
|
|
|
104
|
-
##
|
|
105
|
-
|
|
106
|
-
### Global Header (top-most, full width)
|
|
107
|
-
|
|
108
|
-
Cloudscape `TopNavigation`.
|
|
109
|
-
|
|
110
|
-
| Position | Element | Cloudscape Component | Behavior |
|
|
111
|
-
| -------- | -------- | ------------------------------------------------------ | ---------------------- |
|
|
112
|
-
| Left | Logo | `TopNavigation` `identity` | Navigate to home |
|
|
113
|
-
| Center | Search | `TopNavigation` `search` with `Input` or `Autosuggest` | Global search |
|
|
114
|
-
| Right | Apps | `TopNavigation` utility with `Icon` `grid-view` | Opens dropdown (empty) |
|
|
115
|
-
| Right | Settings | `TopNavigation` utility with `Icon` `settings` | Opens dropdown (empty) |
|
|
116
|
-
| Right | User | `TopNavigation` utility with `Icon` `user-profile` | User menu |
|
|
117
|
-
|
|
118
|
-
### Service Header (below Global Header, full width)
|
|
119
|
-
|
|
120
|
-
Cloudscape `AppLayoutToolbar`.
|
|
121
|
-
|
|
122
|
-
| Position | Element | Cloudscape Component | Behavior |
|
|
123
|
-
| -------- | ------------ | ------------------------------------------------ | ------------------------ |
|
|
124
|
-
| Left | Menu | `Button` (icon-only) with `Icon` `menu` | Toggles Left Panel |
|
|
125
|
-
| Left | Service Name | Text | Current service name |
|
|
126
|
-
| Center | Breadcrumbs | `BreadcrumbGroup` | Single breadcrumb source |
|
|
127
|
-
| Right | Panel Toggle | `Button` (icon-only) with `Icon` `view-vertical` | Toggles Right Panel |
|
|
128
|
-
|
|
129
|
-
### Left Panel
|
|
98
|
+
## UI Components
|
|
130
99
|
|
|
131
|
-
|
|
132
|
-
- Component: `SideNavigation`
|
|
133
|
-
- Header: `Header` with an icon-only `Button` (`Icon` `angle-left`) to collapse
|
|
134
|
-
- Content: Empty placeholder list (service provides content)
|
|
100
|
+
App Shell provides a comprehensive set of UI components built with Radix UI and Tailwind CSS:
|
|
135
101
|
|
|
136
|
-
###
|
|
102
|
+
### Layout Components
|
|
137
103
|
|
|
138
|
-
|
|
139
|
-
|
|
104
|
+
| Component | Description |
|
|
105
|
+
| --------- | ----------- |
|
|
106
|
+
| `AppShell` | Main layout wrapper with header, navigation, and content areas |
|
|
107
|
+
| `SpaceBetween` | Flexbox container with consistent gap sizing (xxxs to xxl) |
|
|
140
108
|
|
|
141
|
-
###
|
|
109
|
+
### Form & Input Components
|
|
142
110
|
|
|
143
|
-
|
|
144
|
-
|
|
111
|
+
| Component | Description |
|
|
112
|
+
| --------- | ----------- |
|
|
113
|
+
| `Button` | Primary, normal, outline, ghost, link, and destructive variants |
|
|
114
|
+
| `Input` | Text input with validation states |
|
|
115
|
+
| `Select` | Dropdown selection with search/filter support |
|
|
116
|
+
| `Toggle` | On/off switch component |
|
|
145
117
|
|
|
146
|
-
###
|
|
118
|
+
### Display Components
|
|
147
119
|
|
|
148
|
-
|
|
120
|
+
| Component | Description |
|
|
121
|
+
| --------- | ----------- |
|
|
122
|
+
| `Badge` | Status indicators with color variants (blue, green, grey, red) |
|
|
123
|
+
| `Avatar` | User/entity avatars with fallback initials |
|
|
124
|
+
| `Card` | Content container with header/footer slots |
|
|
149
125
|
|
|
150
|
-
|
|
126
|
+
### Data Components
|
|
151
127
|
|
|
152
|
-
|
|
153
|
-
|
|
128
|
+
| Component | Description |
|
|
129
|
+
| --------- | ----------- |
|
|
130
|
+
| `DataTable` | Full-featured table with sorting, filtering, and pagination |
|
|
131
|
+
| `SectionedListBoard` | Kanban-style board with drag-and-drop |
|
|
132
|
+
| `SectionedListTable` | Grouped list view with collapsible sections |
|
|
154
133
|
|
|
155
134
|
## Service Catalog Dependency
|
|
156
135
|
|
|
157
|
-
The App Shell builds the **All services** menu and global search suggestions from
|
|
158
|
-
`@mostrom/service-catalog`. Until we move to a monorepo workspace setup, each
|
|
159
|
-
app should explicitly depend on this package to avoid module resolution issues.
|
|
136
|
+
The App Shell builds the **All services** menu and global search suggestions from service-catalog.
|
|
160
137
|
|
|
161
|
-
|
|
138
|
+
Use this alias in consuming apps:
|
|
162
139
|
|
|
163
140
|
```json
|
|
164
141
|
{
|
|
165
|
-
"@
|
|
142
|
+
"@platform/service-catalog": "npm:@mostrom/service-catalog@latest"
|
|
166
143
|
}
|
|
167
144
|
```
|
|
168
145
|
|
|
169
146
|
## Notes
|
|
170
147
|
|
|
171
|
-
-
|
|
172
|
-
-
|
|
148
|
+
- Use the provided UI components for consistent styling across all services.
|
|
149
|
+
- Import `@platform/app-shell/styles.css` in your app's entry point.
|
package/bun.lock
CHANGED
|
@@ -35,9 +35,11 @@
|
|
|
35
35
|
"vaul": "^1.1.2",
|
|
36
36
|
"zod": "^4.3.6",
|
|
37
37
|
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/react": "19.2.14",
|
|
40
|
+
"@types/react-dom": "19.2.3",
|
|
41
|
+
},
|
|
38
42
|
"peerDependencies": {
|
|
39
|
-
"@types/react": "^19.0.0",
|
|
40
|
-
"@types/react-dom": "^19.0.0",
|
|
41
43
|
"react": "^19.0.0",
|
|
42
44
|
"react-dom": "^19.0.0",
|
|
43
45
|
},
|
|
@@ -242,7 +244,7 @@
|
|
|
242
244
|
|
|
243
245
|
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
|
|
244
246
|
|
|
245
|
-
"@types/react": ["@types/react@19.2.
|
|
247
|
+
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
|
|
246
248
|
|
|
247
249
|
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
|
248
250
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostrom/app-shell",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"app-shell": "./bin/init.js",
|
|
8
|
-
"app-shell-init": "./bin/init.js"
|
|
9
|
-
},
|
|
10
6
|
"exports": {
|
|
11
7
|
".": "./src/index.ts",
|
|
12
8
|
"./styles.css": "./src/styles.css",
|
|
@@ -27,14 +23,13 @@
|
|
|
27
23
|
},
|
|
28
24
|
"dependencies": {
|
|
29
25
|
"@base-ui/react": "^1.1.0",
|
|
30
|
-
"@cloudscape-design/components": "*",
|
|
31
|
-
"@cloudscape-design/global-styles": "*",
|
|
32
26
|
"@dnd-kit/core": "^6.3.1",
|
|
33
27
|
"@dnd-kit/modifiers": "^9.0.0",
|
|
34
28
|
"@dnd-kit/sortable": "^10.0.0",
|
|
35
29
|
"@dnd-kit/utilities": "^3.2.2",
|
|
36
30
|
"@floating-ui/dom": "^1.7.5",
|
|
37
31
|
"@hookform/resolvers": "^5.2.2",
|
|
32
|
+
"@platform/service-catalog": "npm:@mostrom/service-catalog@^0.1.3",
|
|
38
33
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
|
39
34
|
"@tanstack/react-table": "^8.21.3",
|
|
40
35
|
"class-variance-authority": "^0.7.1",
|
|
@@ -53,8 +48,7 @@
|
|
|
53
48
|
"tailwind-merge": "^3.4.0",
|
|
54
49
|
"tw-animate-css": "^1.4.0",
|
|
55
50
|
"vaul": "^1.1.2",
|
|
56
|
-
"zod": "^4.3.6"
|
|
57
|
-
"@mostrom/service-catalog": "^0.1.1"
|
|
51
|
+
"zod": "^4.3.6"
|
|
58
52
|
},
|
|
59
53
|
"devDependencies": {
|
|
60
54
|
"@types/react": "19.2.14",
|
package/scripts/publish-npm.sh
CHANGED
|
@@ -4,14 +4,15 @@ set -eu
|
|
|
4
4
|
usage() {
|
|
5
5
|
cat <<USAGE
|
|
6
6
|
Usage:
|
|
7
|
-
./scripts/publish-npm.sh --version <version> [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
8
|
-
./scripts/publish-npm.sh <version> [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
7
|
+
./scripts/publish-npm.sh [--version <version>] [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
8
|
+
./scripts/publish-npm.sh [<version>] [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
9
9
|
|
|
10
10
|
Examples:
|
|
11
|
+
./scripts/publish-npm.sh
|
|
11
12
|
./scripts/publish-npm.sh 0.1.0
|
|
12
13
|
./scripts/publish-npm.sh --version 0.1.0 --scope @mostrom --tag next
|
|
13
14
|
./scripts/publish-npm.sh --version 0.1.0 --scope mostrom --otp 123456
|
|
14
|
-
./scripts/publish-npm.sh --
|
|
15
|
+
./scripts/publish-npm.sh --dry-run
|
|
15
16
|
USAGE
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -19,6 +20,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
19
20
|
APP_SHELL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
20
21
|
PACKAGES_DIR="$(cd "${APP_SHELL_DIR}/.." && pwd)"
|
|
21
22
|
SERVICE_CATALOG_DIR="${PACKAGES_DIR}/service-catalog"
|
|
23
|
+
VERSION_STATE_FILE="${SCRIPT_DIR}/.publish-version"
|
|
22
24
|
|
|
23
25
|
VERSION=""
|
|
24
26
|
SCOPE="@mostrom"
|
|
@@ -69,12 +71,6 @@ while [ "$#" -gt 0 ]; do
|
|
|
69
71
|
esac
|
|
70
72
|
done
|
|
71
73
|
|
|
72
|
-
if [ -z "$VERSION" ]; then
|
|
73
|
-
echo "Error: version is required." >&2
|
|
74
|
-
usage
|
|
75
|
-
exit 1
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
74
|
case "$SCOPE" in
|
|
79
75
|
@*) ;;
|
|
80
76
|
*) SCOPE="@$SCOPE" ;;
|
|
@@ -89,6 +85,54 @@ fi
|
|
|
89
85
|
SERVICE_CATALOG_PACKAGE_NAME="${SCOPE}/service-catalog"
|
|
90
86
|
APP_SHELL_PACKAGE_NAME="${SCOPE}/app-shell"
|
|
91
87
|
|
|
88
|
+
bump_patch_version() {
|
|
89
|
+
current_version="$1"
|
|
90
|
+
CURRENT_VERSION="$current_version" node - <<'NODE'
|
|
91
|
+
const value = process.env.CURRENT_VERSION;
|
|
92
|
+
if (!/^\d+\.\d+\.\d+$/.test(value || "")) {
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const [major, minor, patch] = value.split('.').map(Number);
|
|
96
|
+
process.stdout.write(`${major}.${minor}.${patch + 1}`);
|
|
97
|
+
NODE
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
infer_next_version() {
|
|
101
|
+
if [ -f "$VERSION_STATE_FILE" ]; then
|
|
102
|
+
last_version="$(tr -d '[:space:]' < "$VERSION_STATE_FILE")"
|
|
103
|
+
if [ -z "$last_version" ]; then
|
|
104
|
+
echo "Error: $VERSION_STATE_FILE is empty. Pass --version explicitly once." >&2
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
next_version="$(bump_patch_version "$last_version" || true)"
|
|
108
|
+
if [ -z "$next_version" ]; then
|
|
109
|
+
echo "Error: invalid version in $VERSION_STATE_FILE ($last_version). Pass --version explicitly once." >&2
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
echo "$next_version"
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
latest_registry_version="$(npm view "$SERVICE_CATALOG_PACKAGE_NAME" version 2>/dev/null || true)"
|
|
117
|
+
if [ -n "$latest_registry_version" ]; then
|
|
118
|
+
next_version="$(bump_patch_version "$latest_registry_version" || true)"
|
|
119
|
+
if [ -z "$next_version" ]; then
|
|
120
|
+
echo "Error: failed to parse latest registry version ($latest_registry_version). Pass --version explicitly." >&2
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
echo "$next_version"
|
|
124
|
+
return 0
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
echo "Error: Could not infer next version. Pass --version explicitly once (for example: --version 0.1.0)." >&2
|
|
128
|
+
exit 1
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if [ -z "$VERSION" ]; then
|
|
132
|
+
VERSION="$(infer_next_version)"
|
|
133
|
+
echo "==> Auto-incremented version: ${VERSION}"
|
|
134
|
+
fi
|
|
135
|
+
|
|
92
136
|
TMP_DIR="$(mktemp -d)"
|
|
93
137
|
cleanup() {
|
|
94
138
|
rm -rf "$TMP_DIR"
|
|
@@ -126,6 +170,7 @@ copy_pkg() {
|
|
|
126
170
|
--exclude .env \
|
|
127
171
|
--exclude test-results \
|
|
128
172
|
--exclude .DS_Store \
|
|
173
|
+
--exclude scripts/.publish-version \
|
|
129
174
|
"$from_dir/" "$to_dir/"
|
|
130
175
|
}
|
|
131
176
|
|
|
@@ -135,12 +180,14 @@ rewrite_manifest() {
|
|
|
135
180
|
package_name="$3"
|
|
136
181
|
service_catalog_package="${4:-}"
|
|
137
182
|
service_catalog_range="${5:-}"
|
|
183
|
+
service_catalog_alias="${6:-}"
|
|
138
184
|
|
|
139
185
|
MANIFEST_PATH="$manifest_path" \
|
|
140
186
|
PACKAGE_VERSION="$package_version" \
|
|
141
187
|
PACKAGE_NAME="$package_name" \
|
|
142
188
|
SERVICE_CATALOG_PACKAGE="$service_catalog_package" \
|
|
143
189
|
SERVICE_CATALOG_RANGE="$service_catalog_range" \
|
|
190
|
+
SERVICE_CATALOG_ALIAS="$service_catalog_alias" \
|
|
144
191
|
node - <<'NODE'
|
|
145
192
|
const fs = require('fs');
|
|
146
193
|
const p = process.env.MANIFEST_PATH;
|
|
@@ -148,15 +195,18 @@ const version = process.env.PACKAGE_VERSION;
|
|
|
148
195
|
const packageName = process.env.PACKAGE_NAME;
|
|
149
196
|
const serviceCatalogPackage = process.env.SERVICE_CATALOG_PACKAGE;
|
|
150
197
|
const serviceCatalogRange = process.env.SERVICE_CATALOG_RANGE;
|
|
198
|
+
const serviceCatalogAlias = process.env.SERVICE_CATALOG_ALIAS;
|
|
151
199
|
const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
152
200
|
pkg.name = packageName;
|
|
153
201
|
pkg.version = version;
|
|
154
202
|
pkg.private = false;
|
|
155
203
|
pkg.publishConfig = { ...(pkg.publishConfig || {}), access: 'public' };
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
204
|
+
if (serviceCatalogAlias) {
|
|
205
|
+
pkg.dependencies = { ...(pkg.dependencies || {}), ['@platform/service-catalog']: serviceCatalogAlias };
|
|
206
|
+
if (serviceCatalogPackage && pkg.dependencies && pkg.dependencies[serviceCatalogPackage]) {
|
|
207
|
+
delete pkg.dependencies[serviceCatalogPackage];
|
|
208
|
+
}
|
|
209
|
+
} else if (serviceCatalogPackage && serviceCatalogRange) {
|
|
160
210
|
pkg.dependencies = { ...(pkg.dependencies || {}), [serviceCatalogPackage]: serviceCatalogRange };
|
|
161
211
|
}
|
|
162
212
|
fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n');
|
|
@@ -171,7 +221,7 @@ copy_pkg "$SERVICE_CATALOG_DIR" "$SERVICE_TMP_DIR"
|
|
|
171
221
|
copy_pkg "$APP_SHELL_DIR" "$APP_SHELL_TMP_DIR"
|
|
172
222
|
|
|
173
223
|
rewrite_manifest "${SERVICE_TMP_DIR}/package.json" "$VERSION" "$SERVICE_CATALOG_PACKAGE_NAME"
|
|
174
|
-
rewrite_manifest "${APP_SHELL_TMP_DIR}/package.json" "$VERSION" "$APP_SHELL_PACKAGE_NAME" "$SERVICE_CATALOG_PACKAGE_NAME" "^${VERSION}"
|
|
224
|
+
rewrite_manifest "${APP_SHELL_TMP_DIR}/package.json" "$VERSION" "$APP_SHELL_PACKAGE_NAME" "$SERVICE_CATALOG_PACKAGE_NAME" "^${VERSION}" "npm:${SERVICE_CATALOG_PACKAGE_NAME}@^${VERSION}"
|
|
175
225
|
|
|
176
226
|
publish_pkg() {
|
|
177
227
|
pkg_dir="$1"
|
|
@@ -196,7 +246,14 @@ publish_pkg() {
|
|
|
196
246
|
publish_pkg "$SERVICE_TMP_DIR" "$SERVICE_CATALOG_PACKAGE_NAME"
|
|
197
247
|
publish_pkg "$APP_SHELL_TMP_DIR" "$APP_SHELL_PACKAGE_NAME"
|
|
198
248
|
|
|
249
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
250
|
+
printf "%s\n" "$VERSION" > "$VERSION_STATE_FILE"
|
|
251
|
+
fi
|
|
252
|
+
|
|
199
253
|
echo "==> Done"
|
|
200
254
|
echo "Published version: ${VERSION}"
|
|
201
255
|
echo "Scope: ${SCOPE}"
|
|
202
256
|
echo "Tag: ${TAG}"
|
|
257
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
258
|
+
echo "Version state file: ${VERSION_STATE_FILE}"
|
|
259
|
+
fi
|
package/src/AppShell.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AppShell Component
|
|
3
3
|
*
|
|
4
|
-
* The primary layout wrapper for all platform services.
|
|
5
|
-
*
|
|
4
|
+
* The primary layout wrapper for all platform services. Provides consistent
|
|
5
|
+
* visual and behavioral patterns across the platform.
|
|
6
6
|
*
|
|
7
7
|
* LAYOUT STRUCTURE:
|
|
8
8
|
* ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
|
|
44
44
|
import React from "react";
|
|
45
45
|
|
|
46
|
-
import "@cloudscape-design/global-styles/index.css";
|
|
47
46
|
import "./styles.css";
|
|
48
47
|
|
|
49
48
|
import { AppFlashbar, type FlashbarMessage } from "./components/layout/AppFlashbar";
|
|
@@ -72,7 +71,7 @@ import { GlobalHeaderSearch } from "./components/global-header/GlobalHeaderSearc
|
|
|
72
71
|
import { type SearchOption } from "./components/search/GlobalSearch";
|
|
73
72
|
import { HeaderUtilities } from "./components/global-header/HeaderUtilities";
|
|
74
73
|
|
|
75
|
-
/**
|
|
74
|
+
/** Drawer configuration for slide-in panels */
|
|
76
75
|
interface Drawer {
|
|
77
76
|
id: string;
|
|
78
77
|
ariaLabels?: {
|
|
@@ -640,10 +639,9 @@ export function AppShell({
|
|
|
640
639
|
* Left-side collapsible panel containing service-specific navigation.
|
|
641
640
|
* Shows the service name in the header and hierarchical navigation items.
|
|
642
641
|
*/
|
|
643
|
-
// Cast to internal type - both Cloudscape and custom types share the same shape
|
|
644
642
|
const normalizedNavigationItems = (navigationItems ?? []) as ReadonlyArray<NavigationItem>;
|
|
645
643
|
|
|
646
|
-
// Adapter to normalize
|
|
644
|
+
// Adapter to normalize NavigationFollowEvent
|
|
647
645
|
const handleNavigationFollow = onNavigationFollow
|
|
648
646
|
? (event: NavigationFollowEvent) => {
|
|
649
647
|
onNavigationFollow(event as CompatibleNavigationFollowEvent);
|
|
@@ -27,6 +27,6 @@ export type {
|
|
|
27
27
|
export { CreateButtonGroup } from "../ui/create-button-group"
|
|
28
28
|
export type { CreateButtonGroupProps } from "../ui/create-button-group"
|
|
29
29
|
|
|
30
|
-
// Actions dropdown
|
|
30
|
+
// Actions dropdown
|
|
31
31
|
export { ActionsDropdown } from "../ui/actions-dropdown"
|
|
32
32
|
export type { ActionsDropdownProps, ActionsDropdownItem } from "../ui/actions-dropdown"
|
|
@@ -2,7 +2,7 @@ import { useState, useMemo, type MouseEvent } from "react";
|
|
|
2
2
|
|
|
3
3
|
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
|
4
4
|
|
|
5
|
-
//
|
|
5
|
+
// Menu dropdown types
|
|
6
6
|
export interface MenuDropdownItem {
|
|
7
7
|
id: string;
|
|
8
8
|
text: string;
|
|
@@ -26,7 +26,6 @@ export interface AppBreadcrumbProps {
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* AppBreadcrumb - A wrapper around reui Breadcrumb components
|
|
29
|
-
* that provides a similar API to Cloudscape's BreadcrumbGroup
|
|
30
29
|
*/
|
|
31
30
|
export function AppBreadcrumb({ items, onFollow, className }: AppBreadcrumbProps) {
|
|
32
31
|
if (!items || items.length === 0) {
|
|
@@ -54,7 +54,7 @@ const HEADER_HEIGHT = 56;
|
|
|
54
54
|
const SERVICE_BAR_HEIGHT = 56;
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* AppLayout - A custom layout component
|
|
57
|
+
* AppLayout - A custom layout component for platform services.
|
|
58
58
|
*
|
|
59
59
|
* Layout structure:
|
|
60
60
|
* ┌──────────────────────────────────────────────────────────────────────┐
|
|
@@ -100,8 +100,8 @@ export interface AppNavigationProps {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* AppNavigation - A navigation component
|
|
104
|
-
*
|
|
103
|
+
* AppNavigation - A navigation component using Tailwind styling.
|
|
104
|
+
* Designed to work within AppLayout's navigation slot.
|
|
105
105
|
*/
|
|
106
106
|
export function AppNavigation({
|
|
107
107
|
serviceName,
|
|
@@ -35,8 +35,7 @@ export interface AppSidebarProps {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* AppSidebar - A sidebar wrapper
|
|
39
|
-
* using shadcn Sidebar components internally.
|
|
38
|
+
* AppSidebar - A sidebar wrapper using shadcn Sidebar components internally.
|
|
40
39
|
*/
|
|
41
40
|
export function AppSidebar({
|
|
42
41
|
serviceName,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as Popover from "@radix-ui/react-popover";
|
|
3
|
-
import Badge from "
|
|
4
|
-
import Button from "
|
|
5
|
-
import SpaceBetween from "
|
|
3
|
+
import { Badge } from "../ui/badge";
|
|
4
|
+
import { Button } from "../ui/button";
|
|
5
|
+
import { SpaceBetween } from "../ui/space-between";
|
|
6
6
|
import { format, isToday, isTomorrow, isValid, parseISO } from "date-fns";
|
|
7
7
|
import {
|
|
8
8
|
DateSelector,
|
|
@@ -69,7 +69,7 @@ function ExampleTable({ sections }: { sections: Section<Deal>[] }) {
|
|
|
69
69
|
- `type`:
|
|
70
70
|
- `text`: plain string rendering.
|
|
71
71
|
- `currency`: localized currency formatting.
|
|
72
|
-
- `badge`:
|
|
72
|
+
- `badge`: badge with optional `badgeColorMap`.
|
|
73
73
|
- `avatar`: initials avatar from string field.
|
|
74
74
|
- `editable`: defaults to editable for `text`; set `false` to lock.
|
|
75
75
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import Badge from "
|
|
2
|
+
import { Badge } from "../ui/badge";
|
|
3
3
|
import type { Assignee, ColumnDefinition, TableBadgeColor } from "./types";
|
|
4
4
|
import { AssigneeSelector } from "@/components/ui/assignee-selector";
|
|
5
5
|
|
|
@@ -43,7 +43,6 @@ export interface ActionsDropdownProps {
|
|
|
43
43
|
/**
|
|
44
44
|
* ActionsDropdown - A dropdown menu for action buttons.
|
|
45
45
|
*
|
|
46
|
-
* This component replaces Cloudscape's ButtonDropdown with our design system.
|
|
47
46
|
* Use it for action menus like "Actions", "More options", etc.
|
|
48
47
|
*
|
|
49
48
|
* @example
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
import { Slot } from "radix-ui"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
13
|
+
secondary:
|
|
14
|
+
"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
15
|
+
destructive:
|
|
16
|
+
"bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
17
|
+
outline:
|
|
18
|
+
"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
19
|
+
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
20
|
+
link: "text-primary underline-offset-4 [a&]:hover:underline",
|
|
21
|
+
},
|
|
22
|
+
// Color variants for status indicators
|
|
23
|
+
color: {
|
|
24
|
+
blue: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
|
|
25
|
+
green: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
|
|
26
|
+
grey: "bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200",
|
|
27
|
+
red: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: "default",
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
function Badge({
|
|
37
|
+
className,
|
|
38
|
+
variant,
|
|
39
|
+
color,
|
|
40
|
+
asChild = false,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<"span"> &
|
|
43
|
+
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
44
|
+
const Comp = asChild ? Slot.Root : "span"
|
|
45
|
+
|
|
46
|
+
// If color is provided, use color variant; otherwise use variant (defaulting to "default")
|
|
47
|
+
const resolvedVariant = color ? undefined : (variant ?? "default")
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Comp
|
|
51
|
+
data-slot="badge"
|
|
52
|
+
data-variant={color ?? variant}
|
|
53
|
+
className={cn(badgeVariants({ variant: resolvedVariant, color }), className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Badge, badgeVariants }
|