hale-commenting-system 2.2.0 → 2.2.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.
- package/.claude/settings.local.json +7 -0
- package/.editorconfig +17 -0
- package/.eslintrc.js +75 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
- package/.github/workflows/ci.yaml +51 -0
- package/.prettierignore +1 -0
- package/.prettierrc +4 -0
- package/GITHUB_OAUTH_ENV_TEMPLATE.md +53 -0
- package/LICENSE +21 -0
- package/README.md +92 -21
- package/package.json +74 -50
- package/scripts/README.md +42 -0
- package/scripts/integrate.js +440 -0
- package/src/app/AppLayout/AppLayout.tsx +248 -0
- package/src/app/Comments/Comments.tsx +273 -0
- package/src/app/Dashboard/Dashboard.tsx +10 -0
- package/src/app/NotFound/NotFound.tsx +35 -0
- package/src/app/Settings/General/GeneralSettings.tsx +16 -0
- package/src/app/Settings/Profile/ProfileSettings.tsx +18 -0
- package/src/app/Support/Support.tsx +50 -0
- package/src/app/__snapshots__/app.test.tsx.snap +524 -0
- package/src/app/app.css +11 -0
- package/src/app/app.test.tsx +55 -0
- package/src/app/bgimages/Patternfly-Logo.svg +28 -0
- package/src/app/commenting-system/components/CommentOverlay.tsx +93 -0
- package/src/app/commenting-system/components/CommentPanel.tsx +534 -0
- package/src/app/commenting-system/components/CommentPin.tsx +60 -0
- package/src/app/commenting-system/components/DetailsTab.tsx +516 -0
- package/src/app/commenting-system/components/FloatingWidget.tsx +130 -0
- package/src/app/commenting-system/components/JiraTab.tsx +696 -0
- package/src/app/commenting-system/contexts/CommentContext.tsx +1033 -0
- package/src/app/commenting-system/contexts/GitHubAuthContext.tsx +84 -0
- package/{dist/index.d.ts → src/app/commenting-system/index.ts} +5 -4
- package/src/app/commenting-system/services/githubAdapter.ts +359 -0
- package/src/app/commenting-system/types/index.ts +27 -0
- package/src/app/commenting-system/utils/version.ts +19 -0
- package/src/app/index.tsx +22 -0
- package/src/app/routes.tsx +81 -0
- package/src/app/utils/useDocumentTitle.ts +13 -0
- package/src/favicon.png +0 -0
- package/src/index.html +18 -0
- package/src/index.tsx +25 -0
- package/src/test/setup.ts +33 -0
- package/src/typings.d.ts +12 -0
- package/stylePaths.js +14 -0
- package/tsconfig.json +34 -0
- package/vitest.config.ts +19 -0
- package/webpack.common.js +139 -0
- package/webpack.dev.js +318 -0
- package/webpack.prod.js +38 -0
- package/bin/detect.d.ts +0 -10
- package/bin/detect.js +0 -134
- package/bin/generators.d.ts +0 -20
- package/bin/generators.js +0 -272
- package/bin/hale-commenting.js +0 -4
- package/bin/index.d.ts +0 -2
- package/bin/index.js +0 -61
- package/bin/onboarding.d.ts +0 -1
- package/bin/onboarding.js +0 -395
- package/bin/postinstall.d.ts +0 -2
- package/bin/postinstall.js +0 -65
- package/bin/validators.d.ts +0 -2
- package/bin/validators.js +0 -66
- package/dist/cli/detect.d.ts +0 -10
- package/dist/cli/detect.js +0 -134
- package/dist/cli/generators.d.ts +0 -20
- package/dist/cli/generators.js +0 -272
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -61
- package/dist/cli/onboarding.d.ts +0 -1
- package/dist/cli/onboarding.js +0 -395
- package/dist/cli/postinstall.d.ts +0 -2
- package/dist/cli/postinstall.js +0 -65
- package/dist/cli/validators.d.ts +0 -2
- package/dist/cli/validators.js +0 -66
- package/dist/components/CommentOverlay.d.ts +0 -2
- package/dist/components/CommentOverlay.js +0 -101
- package/dist/components/CommentPanel.d.ts +0 -6
- package/dist/components/CommentPanel.js +0 -334
- package/dist/components/CommentPin.d.ts +0 -11
- package/dist/components/CommentPin.js +0 -64
- package/dist/components/DetailsTab.d.ts +0 -2
- package/dist/components/DetailsTab.js +0 -380
- package/dist/components/FloatingWidget.d.ts +0 -8
- package/dist/components/FloatingWidget.js +0 -128
- package/dist/components/JiraTab.d.ts +0 -2
- package/dist/components/JiraTab.js +0 -507
- package/dist/contexts/CommentContext.d.ts +0 -30
- package/dist/contexts/CommentContext.js +0 -891
- package/dist/contexts/GitHubAuthContext.d.ts +0 -13
- package/dist/contexts/GitHubAuthContext.js +0 -96
- package/dist/index.js +0 -27
- package/dist/services/githubAdapter.d.ts +0 -56
- package/dist/services/githubAdapter.js +0 -321
- package/dist/types/index.d.ts +0 -25
- package/dist/types/index.js +0 -2
- package/dist/utils/version.d.ts +0 -1
- package/dist/utils/version.js +0 -23
- package/templates/webpack-middleware.js +0 -226
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.DetailsTab = void 0;
|
|
37
|
-
const React = __importStar(require("react"));
|
|
38
|
-
const react_router_dom_1 = require("react-router-dom");
|
|
39
|
-
const react_core_1 = require("@patternfly/react-core");
|
|
40
|
-
const githubAdapter_1 = require("../services/githubAdapter");
|
|
41
|
-
const STORAGE_KEY = 'hale_commenting_details_v1';
|
|
42
|
-
const GH_DETAILS_PATH = '.hale/details.json';
|
|
43
|
-
function safeParseStore(raw) {
|
|
44
|
-
if (!raw)
|
|
45
|
-
return {};
|
|
46
|
-
try {
|
|
47
|
-
const parsed = JSON.parse(raw);
|
|
48
|
-
if (!parsed || typeof parsed !== 'object')
|
|
49
|
-
return {};
|
|
50
|
-
return parsed;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return {};
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function getStore() {
|
|
57
|
-
if (typeof window === 'undefined')
|
|
58
|
-
return {};
|
|
59
|
-
return safeParseStore(window.localStorage.getItem(STORAGE_KEY));
|
|
60
|
-
}
|
|
61
|
-
function setStore(next) {
|
|
62
|
-
if (typeof window === 'undefined')
|
|
63
|
-
return;
|
|
64
|
-
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(next));
|
|
65
|
-
}
|
|
66
|
-
function normalizePathname(pathname) {
|
|
67
|
-
if (!pathname)
|
|
68
|
-
return '/';
|
|
69
|
-
const cleaned = pathname.split('?')[0].split('#')[0];
|
|
70
|
-
return cleaned === '' ? '/' : cleaned;
|
|
71
|
-
}
|
|
72
|
-
function getSectionRoute(pathname) {
|
|
73
|
-
const normalized = normalizePathname(pathname);
|
|
74
|
-
const parts = normalized.split('/').filter(Boolean);
|
|
75
|
-
if (parts.length === 0)
|
|
76
|
-
return '/';
|
|
77
|
-
return `/${parts[0]}`;
|
|
78
|
-
}
|
|
79
|
-
function getPageKey(pathname) {
|
|
80
|
-
return `page:${normalizePathname(pathname)}`;
|
|
81
|
-
}
|
|
82
|
-
function getSectionKey(sectionRoute) {
|
|
83
|
-
return `section:${normalizePathname(sectionRoute)}/*`;
|
|
84
|
-
}
|
|
85
|
-
function loadForRoute(pathname) {
|
|
86
|
-
const store = getStore();
|
|
87
|
-
const pageKey = getPageKey(pathname);
|
|
88
|
-
if (store[pageKey])
|
|
89
|
-
return { record: coerceRecord(store[pageKey]), source: 'page' };
|
|
90
|
-
const sectionRoute = getSectionRoute(pathname);
|
|
91
|
-
const sectionKey = getSectionKey(sectionRoute);
|
|
92
|
-
if (store[sectionKey])
|
|
93
|
-
return { record: coerceRecord(store[sectionKey]), source: 'section' };
|
|
94
|
-
return { record: null, source: null };
|
|
95
|
-
}
|
|
96
|
-
function isStructuredRecord(r) {
|
|
97
|
-
return (r &&
|
|
98
|
-
typeof r === 'object' &&
|
|
99
|
-
typeof r.designGoal === 'string' &&
|
|
100
|
-
typeof r.primaryGoals === 'string' &&
|
|
101
|
-
typeof r.keyFeaturesBeingValidated === 'string' &&
|
|
102
|
-
typeof r.targetedUsers === 'string' &&
|
|
103
|
-
(r.scope === 'page' || r.scope === 'section') &&
|
|
104
|
-
typeof r.anchorRoute === 'string' &&
|
|
105
|
-
typeof r.updatedAt === 'string');
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Backward compatibility: older drafts may have { title, body }.
|
|
109
|
-
* We keep them by mapping `body` into Design Goal (best-effort) and leaving the rest blank.
|
|
110
|
-
*/
|
|
111
|
-
function coerceRecord(raw) {
|
|
112
|
-
if (isStructuredRecord(raw))
|
|
113
|
-
return raw;
|
|
114
|
-
const legacyBody = typeof raw?.body === 'string' ? raw.body : '';
|
|
115
|
-
const legacyScope = raw?.scope === 'page' || raw?.scope === 'section' ? raw.scope : 'section';
|
|
116
|
-
const legacyAnchor = typeof raw?.anchorRoute === 'string' ? raw.anchorRoute : '/';
|
|
117
|
-
const legacyUpdatedAt = typeof raw?.updatedAt === 'string' ? raw.updatedAt : new Date().toISOString();
|
|
118
|
-
return {
|
|
119
|
-
designGoal: legacyBody,
|
|
120
|
-
primaryGoals: '',
|
|
121
|
-
keyFeaturesBeingValidated: '',
|
|
122
|
-
targetedUsers: '',
|
|
123
|
-
scope: legacyScope,
|
|
124
|
-
anchorRoute: legacyAnchor,
|
|
125
|
-
updatedAt: legacyUpdatedAt,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
const DetailsTab = () => {
|
|
129
|
-
const location = (0, react_router_dom_1.useLocation)();
|
|
130
|
-
const route = normalizePathname(location.pathname);
|
|
131
|
-
const sectionRoute = getSectionRoute(route);
|
|
132
|
-
const [{ record, source }, setResolved] = React.useState(() => loadForRoute(route));
|
|
133
|
-
const [isEditing, setIsEditing] = React.useState(false);
|
|
134
|
-
const [isLoadingRemote, setIsLoadingRemote] = React.useState(false);
|
|
135
|
-
const [remoteError, setRemoteError] = React.useState(null);
|
|
136
|
-
const remoteShaRef = React.useRef(undefined);
|
|
137
|
-
// editable draft state
|
|
138
|
-
const [draftScope, setDraftScope] = React.useState('section');
|
|
139
|
-
const [draftDesignGoal, setDraftDesignGoal] = React.useState('');
|
|
140
|
-
const [draftPrimaryGoals, setDraftPrimaryGoals] = React.useState('');
|
|
141
|
-
const [draftKeyFeaturesBeingValidated, setDraftKeyFeaturesBeingValidated] = React.useState('');
|
|
142
|
-
const [draftTargetedUsers, setDraftTargetedUsers] = React.useState('');
|
|
143
|
-
React.useEffect(() => {
|
|
144
|
-
// when navigating, refresh resolved record and exit edit mode
|
|
145
|
-
setResolved(loadForRoute(route));
|
|
146
|
-
setIsEditing(false);
|
|
147
|
-
}, [route]);
|
|
148
|
-
// Load Details from GitHub (source of truth) when authenticated; keep localStorage as cache/fallback.
|
|
149
|
-
React.useEffect(() => {
|
|
150
|
-
const load = async () => {
|
|
151
|
-
if (!(0, githubAdapter_1.isGitHubConfigured)())
|
|
152
|
-
return;
|
|
153
|
-
setIsLoadingRemote(true);
|
|
154
|
-
setRemoteError(null);
|
|
155
|
-
try {
|
|
156
|
-
const local = getStore();
|
|
157
|
-
const res = await githubAdapter_1.githubAdapter.getRepoFile(GH_DETAILS_PATH);
|
|
158
|
-
if (!res.success) {
|
|
159
|
-
setRemoteError(res.error || 'Failed to load details from GitHub');
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (!res.data) {
|
|
163
|
-
// No remote file yet. If we already have local details, publish them as the initial remote.
|
|
164
|
-
if (Object.keys(local).length > 0) {
|
|
165
|
-
const created = await githubAdapter_1.githubAdapter.putRepoFile({
|
|
166
|
-
path: GH_DETAILS_PATH,
|
|
167
|
-
text: JSON.stringify(local, null, 2) + '\n',
|
|
168
|
-
message: 'chore(details): initialize details store',
|
|
169
|
-
});
|
|
170
|
-
if (created.success) {
|
|
171
|
-
remoteShaRef.current = created.data?.sha;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
remoteShaRef.current = res.data.sha;
|
|
177
|
-
const parsed = safeParseStore(res.data.text);
|
|
178
|
-
setStore(parsed);
|
|
179
|
-
setResolved(loadForRoute(route));
|
|
180
|
-
}
|
|
181
|
-
finally {
|
|
182
|
-
setIsLoadingRemote(false);
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
void load();
|
|
186
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
187
|
-
}, []);
|
|
188
|
-
const startNew = () => {
|
|
189
|
-
setDraftScope('section');
|
|
190
|
-
setDraftDesignGoal('');
|
|
191
|
-
setDraftPrimaryGoals('');
|
|
192
|
-
setDraftKeyFeaturesBeingValidated('');
|
|
193
|
-
setDraftTargetedUsers('');
|
|
194
|
-
setIsEditing(true);
|
|
195
|
-
};
|
|
196
|
-
const startEdit = (mode) => {
|
|
197
|
-
if (mode === 'override-page') {
|
|
198
|
-
// copy inherited section record into a page-scoped override draft
|
|
199
|
-
setDraftScope('page');
|
|
200
|
-
setDraftDesignGoal(record?.designGoal ?? '');
|
|
201
|
-
setDraftPrimaryGoals(record?.primaryGoals ?? '');
|
|
202
|
-
setDraftKeyFeaturesBeingValidated(record?.keyFeaturesBeingValidated ?? '');
|
|
203
|
-
setDraftTargetedUsers(record?.targetedUsers ?? '');
|
|
204
|
-
setIsEditing(true);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
// edit existing record as-is
|
|
208
|
-
const existingScope = record?.scope ?? 'section';
|
|
209
|
-
setDraftScope(existingScope);
|
|
210
|
-
setDraftDesignGoal(record?.designGoal ?? '');
|
|
211
|
-
setDraftPrimaryGoals(record?.primaryGoals ?? '');
|
|
212
|
-
setDraftKeyFeaturesBeingValidated(record?.keyFeaturesBeingValidated ?? '');
|
|
213
|
-
setDraftTargetedUsers(record?.targetedUsers ?? '');
|
|
214
|
-
setIsEditing(true);
|
|
215
|
-
};
|
|
216
|
-
const save = () => {
|
|
217
|
-
const next = {
|
|
218
|
-
designGoal: draftDesignGoal,
|
|
219
|
-
primaryGoals: draftPrimaryGoals,
|
|
220
|
-
keyFeaturesBeingValidated: draftKeyFeaturesBeingValidated,
|
|
221
|
-
targetedUsers: draftTargetedUsers,
|
|
222
|
-
scope: draftScope,
|
|
223
|
-
anchorRoute: draftScope === 'section' ? sectionRoute : route,
|
|
224
|
-
updatedAt: new Date().toISOString(),
|
|
225
|
-
};
|
|
226
|
-
const store = getStore();
|
|
227
|
-
const key = draftScope === 'section' ? getSectionKey(sectionRoute) : getPageKey(route);
|
|
228
|
-
const nextStore = { ...store, [key]: next };
|
|
229
|
-
setStore(nextStore);
|
|
230
|
-
setResolved(loadForRoute(route));
|
|
231
|
-
setIsEditing(false);
|
|
232
|
-
// Best-effort: persist to GitHub as a repo file so designers/admins can edit outside the codebase.
|
|
233
|
-
if ((0, githubAdapter_1.isGitHubConfigured)()) {
|
|
234
|
-
(async () => {
|
|
235
|
-
const text = JSON.stringify(nextStore, null, 2) + '\n';
|
|
236
|
-
const message = `chore(details): update ${key}`;
|
|
237
|
-
const sha = remoteShaRef.current;
|
|
238
|
-
const write = await githubAdapter_1.githubAdapter.putRepoFile({ path: GH_DETAILS_PATH, text, message, sha });
|
|
239
|
-
if (write.success && write.data?.sha) {
|
|
240
|
-
remoteShaRef.current = write.data.sha;
|
|
241
|
-
setRemoteError(null);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
// If sha mismatch (someone else updated), refetch and retry once.
|
|
245
|
-
const refreshed = await githubAdapter_1.githubAdapter.getRepoFile(GH_DETAILS_PATH);
|
|
246
|
-
if (refreshed.success && refreshed.data?.sha) {
|
|
247
|
-
remoteShaRef.current = refreshed.data.sha;
|
|
248
|
-
const retry = await githubAdapter_1.githubAdapter.putRepoFile({ path: GH_DETAILS_PATH, text, message, sha: refreshed.data.sha });
|
|
249
|
-
if (retry.success && retry.data?.sha) {
|
|
250
|
-
remoteShaRef.current = retry.data.sha;
|
|
251
|
-
setRemoteError(null);
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
setRemoteError(write.error || 'Failed to save details to GitHub');
|
|
256
|
-
})();
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
const remove = () => {
|
|
260
|
-
const store = getStore();
|
|
261
|
-
const keyToRemove = source === 'page' ? getPageKey(route) : source === 'section' ? getSectionKey(sectionRoute) : null;
|
|
262
|
-
if (!keyToRemove)
|
|
263
|
-
return;
|
|
264
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
265
|
-
const { [keyToRemove]: _removed, ...rest } = store;
|
|
266
|
-
setStore(rest);
|
|
267
|
-
setResolved(loadForRoute(route));
|
|
268
|
-
setIsEditing(false);
|
|
269
|
-
if ((0, githubAdapter_1.isGitHubConfigured)()) {
|
|
270
|
-
(async () => {
|
|
271
|
-
const text = JSON.stringify(rest, null, 2) + '\n';
|
|
272
|
-
const message = `chore(details): remove ${keyToRemove}`;
|
|
273
|
-
const sha = remoteShaRef.current;
|
|
274
|
-
const write = await githubAdapter_1.githubAdapter.putRepoFile({ path: GH_DETAILS_PATH, text, message, sha });
|
|
275
|
-
if (write.success && write.data?.sha) {
|
|
276
|
-
remoteShaRef.current = write.data.sha;
|
|
277
|
-
setRemoteError(null);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
setRemoteError(write.error || 'Failed to update details in GitHub');
|
|
281
|
-
})();
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
const scopeLabel = source === 'page'
|
|
285
|
-
? 'This page'
|
|
286
|
-
: source === 'section'
|
|
287
|
-
? `Section (${sectionRoute}/*)`
|
|
288
|
-
: null;
|
|
289
|
-
const remoteStatusLine = (0, githubAdapter_1.isGitHubConfigured)()
|
|
290
|
-
? isLoadingRemote
|
|
291
|
-
? 'Loading details from GitHub…'
|
|
292
|
-
: remoteError
|
|
293
|
-
? `GitHub sync: ${remoteError}`
|
|
294
|
-
: 'GitHub sync enabled'
|
|
295
|
-
: null;
|
|
296
|
-
if (!record && !isEditing) {
|
|
297
|
-
return (React.createElement("div", { style: { display: 'grid', gap: '1rem' } },
|
|
298
|
-
React.createElement("div", { style: { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: '1rem' } },
|
|
299
|
-
React.createElement("div", null,
|
|
300
|
-
React.createElement(react_core_1.Title, { headingLevel: "h3", size: "lg" }, "Details"),
|
|
301
|
-
React.createElement("div", { style: { fontSize: '0.875rem', color: 'var(--pf-t--global--text--color--subtle)' } },
|
|
302
|
-
"No details set for ",
|
|
303
|
-
React.createElement("b", null, route),
|
|
304
|
-
"."),
|
|
305
|
-
remoteStatusLine && (React.createElement("div", { style: { fontSize: '0.75rem', color: 'var(--pf-t--global--text--color--subtle)', marginTop: '0.25rem' } }, remoteStatusLine))),
|
|
306
|
-
React.createElement(react_core_1.Button, { variant: "primary", onClick: startNew }, "Add details")),
|
|
307
|
-
React.createElement(react_core_1.Card, null,
|
|
308
|
-
React.createElement(react_core_1.CardBody, null,
|
|
309
|
-
React.createElement("div", { style: { fontSize: '0.875rem', color: 'var(--pf-t--global--text--color--subtle)' } }, "Add designer notes, design goals, links, and context for reviewers.")))));
|
|
310
|
-
}
|
|
311
|
-
if (isEditing) {
|
|
312
|
-
const effectiveAnchor = draftScope === 'section' ? `${sectionRoute}/*` : route;
|
|
313
|
-
return (React.createElement("div", { style: { display: 'grid', gap: '1rem' } },
|
|
314
|
-
React.createElement("div", { style: { display: 'grid', gap: '0.5rem' } },
|
|
315
|
-
React.createElement("div", null,
|
|
316
|
-
React.createElement(react_core_1.Title, { headingLevel: "h3", size: "lg" }, "Edit details"),
|
|
317
|
-
React.createElement("div", { style: { fontSize: '0.875rem', color: 'var(--pf-t--global--text--color--subtle)' } },
|
|
318
|
-
"Applies to: ",
|
|
319
|
-
React.createElement("b", null, effectiveAnchor)),
|
|
320
|
-
remoteStatusLine && (React.createElement("div", { style: { fontSize: '0.75rem', color: 'var(--pf-t--global--text--color--subtle)', marginTop: '0.25rem' } }, remoteStatusLine))),
|
|
321
|
-
React.createElement("div", { style: { display: 'flex', gap: '0.5rem', flexWrap: 'wrap' } },
|
|
322
|
-
React.createElement(react_core_1.Button, { variant: draftScope === 'page' ? 'primary' : 'secondary', onClick: () => setDraftScope('page') }, "This page only"),
|
|
323
|
-
React.createElement(react_core_1.Button, { variant: draftScope === 'section' ? 'primary' : 'secondary', onClick: () => setDraftScope('section'), isDisabled: sectionRoute === '/' && route === '/' },
|
|
324
|
-
"This section (",
|
|
325
|
-
sectionRoute,
|
|
326
|
-
"/*)"))),
|
|
327
|
-
React.createElement(react_core_1.Card, null,
|
|
328
|
-
React.createElement(react_core_1.CardBody, null,
|
|
329
|
-
React.createElement("div", { style: { display: 'grid', gap: '0.75rem' } },
|
|
330
|
-
React.createElement("div", null,
|
|
331
|
-
React.createElement("div", { style: { fontSize: '0.875rem', marginBottom: '0.25rem' } },
|
|
332
|
-
React.createElement("b", null, "Design Goal")),
|
|
333
|
-
React.createElement(react_core_1.TextArea, { "aria-label": "Design goal", value: draftDesignGoal, onChange: (_e, v) => setDraftDesignGoal(v), rows: 3 })),
|
|
334
|
-
React.createElement("div", null,
|
|
335
|
-
React.createElement("div", { style: { fontSize: '0.875rem', marginBottom: '0.25rem' } },
|
|
336
|
-
React.createElement("b", null, "Primary Goal(s)")),
|
|
337
|
-
React.createElement(react_core_1.TextArea, { "aria-label": "Primary goals", value: draftPrimaryGoals, onChange: (_e, v) => setDraftPrimaryGoals(v), rows: 4 })),
|
|
338
|
-
React.createElement("div", null,
|
|
339
|
-
React.createElement("div", { style: { fontSize: '0.875rem', marginBottom: '0.25rem' } },
|
|
340
|
-
React.createElement("b", null, "Key Feature(s) Being Validated")),
|
|
341
|
-
React.createElement(react_core_1.TextArea, { "aria-label": "Key features being validated", value: draftKeyFeaturesBeingValidated, onChange: (_e, v) => setDraftKeyFeaturesBeingValidated(v), rows: 4 })),
|
|
342
|
-
React.createElement("div", null,
|
|
343
|
-
React.createElement("div", { style: { fontSize: '0.875rem', marginBottom: '0.25rem' } },
|
|
344
|
-
React.createElement("b", null, "Targeted User(s)")),
|
|
345
|
-
React.createElement(react_core_1.TextArea, { "aria-label": "Targeted users", value: draftTargetedUsers, onChange: (_e, v) => setDraftTargetedUsers(v), rows: 4 })),
|
|
346
|
-
React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
|
|
347
|
-
React.createElement(react_core_1.Button, { variant: "primary", onClick: save }, "Save"),
|
|
348
|
-
React.createElement(react_core_1.Button, { variant: "link", onClick: () => setIsEditing(false) }, "Cancel")))))));
|
|
349
|
-
}
|
|
350
|
-
if (!record) {
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
return (React.createElement("div", { style: { display: 'grid', gap: '1rem' } },
|
|
354
|
-
React.createElement("div", { style: { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: '1rem' } },
|
|
355
|
-
React.createElement("div", null,
|
|
356
|
-
React.createElement(react_core_1.Title, { headingLevel: "h3", size: "lg" }, "Details"),
|
|
357
|
-
scopeLabel && (React.createElement("div", { style: { fontSize: '0.875rem', color: 'var(--pf-t--global--text--color--subtle)' } },
|
|
358
|
-
"Source: ",
|
|
359
|
-
React.createElement("b", null, scopeLabel)))),
|
|
360
|
-
React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '4px' } },
|
|
361
|
-
source === 'section' && (React.createElement(react_core_1.Button, { variant: "secondary", onClick: () => startEdit('override-page') }, "Override for this page")),
|
|
362
|
-
React.createElement(react_core_1.Button, { variant: "secondary", onClick: () => startEdit('edit-existing') }, "Edit"))),
|
|
363
|
-
React.createElement(react_core_1.Card, null,
|
|
364
|
-
React.createElement(react_core_1.CardBody, null,
|
|
365
|
-
React.createElement(react_core_1.Title, { headingLevel: "h4", size: "md" }, "Design Goal"),
|
|
366
|
-
React.createElement("div", { style: { marginTop: '0.5rem', whiteSpace: 'pre-wrap' } }, record.designGoal || '—'),
|
|
367
|
-
React.createElement(react_core_1.Title, { headingLevel: "h4", size: "md", style: { marginTop: '1rem' } }, "Primary Goal(s)"),
|
|
368
|
-
React.createElement("div", { style: { marginTop: '0.5rem', whiteSpace: 'pre-wrap' } }, record.primaryGoals || '—'),
|
|
369
|
-
React.createElement(react_core_1.Title, { headingLevel: "h4", size: "md", style: { marginTop: '1rem' } }, "Key Feature(s) Being Validated"),
|
|
370
|
-
React.createElement("div", { style: { marginTop: '0.5rem', whiteSpace: 'pre-wrap' } }, record.keyFeaturesBeingValidated || '—'),
|
|
371
|
-
React.createElement(react_core_1.Title, { headingLevel: "h4", size: "md", style: { marginTop: '1rem' } }, "Targeted User(s)"),
|
|
372
|
-
React.createElement("div", { style: { marginTop: '0.5rem', whiteSpace: 'pre-wrap' } }, record.targetedUsers || '—'),
|
|
373
|
-
React.createElement("div", { style: { marginTop: '0.75rem', fontSize: '0.875rem', color: 'var(--pf-t--global--text--color--subtle)' } },
|
|
374
|
-
"Updated: ",
|
|
375
|
-
new Date(record.updatedAt).toLocaleString()),
|
|
376
|
-
React.createElement(react_core_1.ActionList, { style: { marginTop: '0.75rem' } },
|
|
377
|
-
React.createElement(react_core_1.ActionListItem, null,
|
|
378
|
-
React.createElement(react_core_1.Button, { variant: "link", isDanger: true, onClick: remove }, "Remove")))))));
|
|
379
|
-
};
|
|
380
|
-
exports.DetailsTab = DetailsTab;
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.FloatingWidget = void 0;
|
|
37
|
-
const React = __importStar(require("react"));
|
|
38
|
-
const react_core_1 = require("@patternfly/react-core");
|
|
39
|
-
const react_icons_1 = require("@patternfly/react-icons");
|
|
40
|
-
const FloatingWidget = ({ children, onClose, title = 'Hale Commenting System' }) => {
|
|
41
|
-
const [position, setPosition] = React.useState({ x: window.innerWidth - 520, y: 100 });
|
|
42
|
-
const [isDragging, setIsDragging] = React.useState(false);
|
|
43
|
-
const [dragOffset, setDragOffset] = React.useState({ x: 0, y: 0 });
|
|
44
|
-
const [isMinimized, setIsMinimized] = React.useState(false);
|
|
45
|
-
const widgetRef = React.useRef(null);
|
|
46
|
-
const handleMouseDown = (e) => {
|
|
47
|
-
if (!widgetRef.current)
|
|
48
|
-
return;
|
|
49
|
-
const rect = widgetRef.current.getBoundingClientRect();
|
|
50
|
-
setDragOffset({
|
|
51
|
-
x: e.clientX - rect.left,
|
|
52
|
-
y: e.clientY - rect.top,
|
|
53
|
-
});
|
|
54
|
-
setIsDragging(true);
|
|
55
|
-
};
|
|
56
|
-
React.useEffect(() => {
|
|
57
|
-
if (!isDragging)
|
|
58
|
-
return;
|
|
59
|
-
const handleMouseMove = (e) => {
|
|
60
|
-
setPosition({
|
|
61
|
-
x: e.clientX - dragOffset.x,
|
|
62
|
-
y: e.clientY - dragOffset.y,
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
const handleMouseUp = () => {
|
|
66
|
-
setIsDragging(false);
|
|
67
|
-
};
|
|
68
|
-
document.addEventListener('mousemove', handleMouseMove);
|
|
69
|
-
document.addEventListener('mouseup', handleMouseUp);
|
|
70
|
-
return () => {
|
|
71
|
-
document.removeEventListener('mousemove', handleMouseMove);
|
|
72
|
-
document.removeEventListener('mouseup', handleMouseUp);
|
|
73
|
-
};
|
|
74
|
-
}, [isDragging, dragOffset]);
|
|
75
|
-
// Constrain to viewport but allow dragging header even when partially off-screen
|
|
76
|
-
const constrainedPosition = React.useMemo(() => {
|
|
77
|
-
const widgetWidth = 500;
|
|
78
|
-
const widgetHeight = isMinimized ? 60 : 400;
|
|
79
|
-
const maxX = window.innerWidth - 50; // Allow 50px of widget to be visible for dragging
|
|
80
|
-
const maxY = window.innerHeight - 50;
|
|
81
|
-
return {
|
|
82
|
-
x: Math.max(-widgetWidth + 50, Math.min(position.x, maxX)),
|
|
83
|
-
y: Math.max(-widgetHeight + 50, Math.min(position.y, maxY)),
|
|
84
|
-
};
|
|
85
|
-
}, [position, isMinimized]);
|
|
86
|
-
return (React.createElement("div", { ref: widgetRef, style: {
|
|
87
|
-
position: 'fixed',
|
|
88
|
-
left: `${constrainedPosition.x}px`,
|
|
89
|
-
top: `${constrainedPosition.y}px`,
|
|
90
|
-
width: '500px',
|
|
91
|
-
height: isMinimized ? '60px' : '80vh',
|
|
92
|
-
maxHeight: '80vh',
|
|
93
|
-
zIndex: 10000,
|
|
94
|
-
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.2)',
|
|
95
|
-
borderRadius: 'var(--pf-t--global--border--radius--medium)',
|
|
96
|
-
backgroundColor: '#ffffff',
|
|
97
|
-
display: 'flex',
|
|
98
|
-
flexDirection: 'column',
|
|
99
|
-
cursor: isDragging ? 'grabbing' : 'default',
|
|
100
|
-
} },
|
|
101
|
-
React.createElement("div", { onMouseDown: handleMouseDown, style: {
|
|
102
|
-
padding: '1rem',
|
|
103
|
-
borderBottom: isMinimized ? 'none' : '1px solid var(--pf-t--global--border--color--default)',
|
|
104
|
-
display: 'flex',
|
|
105
|
-
alignItems: 'center',
|
|
106
|
-
justifyContent: 'space-between',
|
|
107
|
-
cursor: 'grab',
|
|
108
|
-
userSelect: 'none',
|
|
109
|
-
backgroundColor: '#ffffff',
|
|
110
|
-
borderRadius: isMinimized ? 'var(--pf-t--global--border--radius--medium)' : 'var(--pf-t--global--border--radius--medium) var(--pf-t--global--border--radius--medium) 0 0',
|
|
111
|
-
} },
|
|
112
|
-
React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: '0.5rem', flex: 1 } },
|
|
113
|
-
React.createElement(react_icons_1.GripVerticalIcon, { style: { color: 'var(--pf-t--global--text--color--subtle)' } }),
|
|
114
|
-
React.createElement(react_core_1.Title, { headingLevel: "h2", size: "lg" }, title)),
|
|
115
|
-
React.createElement("div", { style: { display: 'flex', gap: '0.25rem' } },
|
|
116
|
-
React.createElement(react_core_1.Button, { variant: "plain", icon: React.createElement(react_icons_1.WindowMinimizeIcon, null), onClick: (e) => {
|
|
117
|
-
e.stopPropagation();
|
|
118
|
-
setIsMinimized(!isMinimized);
|
|
119
|
-
}, "aria-label": isMinimized ? 'Maximize widget' : 'Minimize widget' }),
|
|
120
|
-
React.createElement(react_core_1.Button, { variant: "plain", icon: React.createElement(react_icons_1.TimesIcon, null), onClick: onClose, "aria-label": "Close widget" }))),
|
|
121
|
-
!isMinimized && (React.createElement("div", { style: {
|
|
122
|
-
overflow: 'auto',
|
|
123
|
-
flex: 1,
|
|
124
|
-
backgroundColor: '#ffffff',
|
|
125
|
-
borderRadius: '0 0 var(--pf-t--global--border--radius--medium) var(--pf-t--global--border--radius--medium)',
|
|
126
|
-
} }, children))));
|
|
127
|
-
};
|
|
128
|
-
exports.FloatingWidget = FloatingWidget;
|