@teambit/component.ui.version-dropdown 0.0.0-0aa660598a05d04f2b124cb0ae8b4a1c05b66d78
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/dist/index.d.ts +4 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/lane-info/index.d.ts +2 -0
- package/dist/lane-info/index.js +6 -0
- package/dist/lane-info/index.js.map +1 -0
- package/dist/lane-info/lane-info.d.ts +6 -0
- package/dist/lane-info/lane-info.js +20 -0
- package/dist/lane-info/lane-info.js.map +1 -0
- package/dist/lane-info/lane-info.module.scss +27 -0
- package/dist/preview-1753890535938.js +7 -0
- package/dist/version-dropdown-placeholder.d.ts +17 -0
- package/dist/version-dropdown-placeholder.js +92 -0
- package/dist/version-dropdown-placeholder.js.map +1 -0
- package/dist/version-dropdown-placeholder.module.scss +50 -0
- package/dist/version-dropdown.composition.d.ts +3 -0
- package/dist/version-dropdown.composition.js +28 -0
- package/dist/version-dropdown.composition.js.map +1 -0
- package/dist/version-dropdown.d.ts +53 -0
- package/dist/version-dropdown.docs.d.ts +35 -0
- package/dist/version-dropdown.docs.js +67 -0
- package/dist/version-dropdown.docs.js.map +1 -0
- package/dist/version-dropdown.js +153 -0
- package/dist/version-dropdown.js.map +1 -0
- package/dist/version-dropdown.module.scss +128 -0
- package/dist/version-dropdown.spec.d.ts +1 -0
- package/dist/version-dropdown.spec.js +33 -0
- package/dist/version-dropdown.spec.js.map +1 -0
- package/dist/version-info/index.d.ts +2 -0
- package/dist/version-info/index.js +6 -0
- package/dist/version-info/index.js.map +1 -0
- package/dist/version-info/version-info.d.ts +10 -0
- package/dist/version-info/version-info.js +79 -0
- package/dist/version-info/version-info.js.map +1 -0
- package/dist/version-info/version-info.module.scss +54 -0
- package/index.ts +4 -0
- package/lane-info/index.ts +2 -0
- package/lane-info/lane-info.module.scss +27 -0
- package/lane-info/lane-info.tsx +23 -0
- package/package.json +71 -0
- package/types/asset.d.ts +29 -0
- package/types/style.d.ts +42 -0
- package/version-dropdown-placeholder.module.scss +50 -0
- package/version-dropdown-placeholder.tsx +109 -0
- package/version-dropdown.composition.tsx +36 -0
- package/version-dropdown.docs.tsx +68 -0
- package/version-dropdown.module.scss +128 -0
- package/version-dropdown.spec.tsx +29 -0
- package/version-dropdown.tsx +331 -0
- package/version-info/index.ts +2 -0
- package/version-info/version-info.module.scss +54 -0
- package/version-info/version-info.tsx +87 -0
@@ -0,0 +1,331 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { MenuLinkItem } from '@teambit/design.ui.surfaces.menu.link-item';
|
3
|
+
import { Dropdown } from '@teambit/evangelist.surfaces.dropdown';
|
4
|
+
import { Tab } from '@teambit/ui-foundation.ui.use-box.tab';
|
5
|
+
import type { LegacyComponentLog } from '@teambit/legacy-component-log';
|
6
|
+
import { UserAvatar } from '@teambit/design.ui.avatar';
|
7
|
+
import { LineSkeleton } from '@teambit/base-ui.loaders.skeleton';
|
8
|
+
import type { LaneModel } from '@teambit/lanes.ui.models.lanes-model';
|
9
|
+
import classNames from 'classnames';
|
10
|
+
import styles from './version-dropdown.module.scss';
|
11
|
+
import { VersionInfo } from './version-info';
|
12
|
+
import { LaneInfo } from './lane-info';
|
13
|
+
import type { VersionProps } from './version-dropdown-placeholder';
|
14
|
+
import { SimpleVersion } from './version-dropdown-placeholder';
|
15
|
+
|
16
|
+
export const LOCAL_VERSION = 'workspace';
|
17
|
+
|
18
|
+
export type DropdownComponentVersion = Partial<LegacyComponentLog> & { version: string };
|
19
|
+
|
20
|
+
export type UseComponentDropdownVersionsResult = {
|
21
|
+
tags?: DropdownComponentVersion[];
|
22
|
+
snaps?: DropdownComponentVersion[];
|
23
|
+
loading?: boolean;
|
24
|
+
};
|
25
|
+
export type UseComponentDropdownVersionsProps = {
|
26
|
+
skip?: boolean;
|
27
|
+
};
|
28
|
+
export type UseComponentDropdownVersions = (
|
29
|
+
props?: UseComponentDropdownVersionsProps
|
30
|
+
) => UseComponentDropdownVersionsResult;
|
31
|
+
export type GetActiveTabIndex = (
|
32
|
+
currentVersion?: string,
|
33
|
+
tabs?: Array<VersionMenuTab>,
|
34
|
+
tags?: DropdownComponentVersion[],
|
35
|
+
snaps?: DropdownComponentVersion[],
|
36
|
+
currentLane?: LaneModel
|
37
|
+
) => number;
|
38
|
+
export type VersionDropdownProps = {
|
39
|
+
localVersion?: boolean;
|
40
|
+
latestVersion?: string;
|
41
|
+
currentVersion: string;
|
42
|
+
useCurrentVersionLog?: (props?: { skip?: boolean; version?: string }) => DropdownComponentVersion | undefined;
|
43
|
+
hasMoreVersions?: boolean;
|
44
|
+
loading?: boolean;
|
45
|
+
useComponentVersions?: UseComponentDropdownVersions;
|
46
|
+
currentLane?: LaneModel;
|
47
|
+
lanes?: LaneModel[];
|
48
|
+
getActiveTabIndex?: GetActiveTabIndex;
|
49
|
+
overrideVersionHref?: (version: string) => string;
|
50
|
+
placeholderClassName?: string;
|
51
|
+
dropdownClassName?: string;
|
52
|
+
menuClassName?: string;
|
53
|
+
showVersionDetails?: boolean;
|
54
|
+
disabled?: boolean;
|
55
|
+
PlaceholderComponent?: React.ComponentType<VersionProps>;
|
56
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
57
|
+
|
58
|
+
export const VersionDropdown = React.memo(_VersionDropdown);
|
59
|
+
const VersionMenu = React.memo(_VersionMenu);
|
60
|
+
function _VersionDropdown({
|
61
|
+
currentVersion,
|
62
|
+
latestVersion,
|
63
|
+
localVersion,
|
64
|
+
useCurrentVersionLog,
|
65
|
+
hasMoreVersions,
|
66
|
+
loading,
|
67
|
+
overrideVersionHref,
|
68
|
+
className,
|
69
|
+
placeholderClassName,
|
70
|
+
getActiveTabIndex,
|
71
|
+
dropdownClassName,
|
72
|
+
menuClassName,
|
73
|
+
showVersionDetails = true,
|
74
|
+
disabled,
|
75
|
+
PlaceholderComponent: _PlaceholderComponent,
|
76
|
+
currentLane,
|
77
|
+
useComponentVersions,
|
78
|
+
lanes,
|
79
|
+
...rest
|
80
|
+
}: VersionDropdownProps) {
|
81
|
+
const [key, setKey] = useState(0);
|
82
|
+
const singleVersion = !hasMoreVersions;
|
83
|
+
const [open, setOpen] = useState(false);
|
84
|
+
|
85
|
+
React.useEffect(() => {
|
86
|
+
if (loading && open) {
|
87
|
+
setOpen(false);
|
88
|
+
}
|
89
|
+
}, [loading]);
|
90
|
+
|
91
|
+
const handlePlaceholderClicked = (e: React.MouseEvent<HTMLDivElement>) => {
|
92
|
+
if (loading) return;
|
93
|
+
if (e.target === e.currentTarget) {
|
94
|
+
setOpen((o) => !o);
|
95
|
+
}
|
96
|
+
};
|
97
|
+
|
98
|
+
const defaultPlaceholder = (
|
99
|
+
<SimpleVersion
|
100
|
+
useCurrentVersionLog={useCurrentVersionLog}
|
101
|
+
disabled={disabled}
|
102
|
+
className={placeholderClassName}
|
103
|
+
currentVersion={currentVersion}
|
104
|
+
onClick={handlePlaceholderClicked}
|
105
|
+
hasMoreVersions={hasMoreVersions}
|
106
|
+
loading={loading}
|
107
|
+
showFullVersion={currentVersion === 'workspace'}
|
108
|
+
/>
|
109
|
+
);
|
110
|
+
|
111
|
+
const PlaceholderComponent = _PlaceholderComponent ? (
|
112
|
+
<_PlaceholderComponent
|
113
|
+
useCurrentVersionLog={useCurrentVersionLog}
|
114
|
+
disabled={disabled}
|
115
|
+
className={placeholderClassName}
|
116
|
+
currentVersion={currentVersion}
|
117
|
+
onClick={handlePlaceholderClicked}
|
118
|
+
hasMoreVersions={hasMoreVersions}
|
119
|
+
loading={loading}
|
120
|
+
showFullVersion={currentVersion === 'workspace'}
|
121
|
+
/>
|
122
|
+
) : (
|
123
|
+
defaultPlaceholder
|
124
|
+
);
|
125
|
+
|
126
|
+
if (disabled || (singleVersion && !loading)) {
|
127
|
+
return <div className={classNames(styles.noVersions, className)}>{PlaceholderComponent}</div>;
|
128
|
+
}
|
129
|
+
|
130
|
+
return (
|
131
|
+
<div {...rest} className={classNames(styles.versionDropdown, className)}>
|
132
|
+
<Dropdown
|
133
|
+
className={classNames(styles.dropdown, dropdownClassName)}
|
134
|
+
dropClass={classNames(styles.menu, menuClassName)}
|
135
|
+
open={open}
|
136
|
+
onClick={handlePlaceholderClicked}
|
137
|
+
onClickOutside={() => setOpen(false)}
|
138
|
+
onChange={(_e, _open) => _open && setKey((x) => x + 1)} // to reset menu to initial state when toggling
|
139
|
+
PlaceholderComponent={({ children, ...other }) => (
|
140
|
+
<div {...other} className={placeholderClassName} onClick={handlePlaceholderClicked}>
|
141
|
+
{children}
|
142
|
+
</div>
|
143
|
+
)}
|
144
|
+
placeholder={PlaceholderComponent}
|
145
|
+
>
|
146
|
+
<VersionMenu
|
147
|
+
className={menuClassName}
|
148
|
+
key={key}
|
149
|
+
currentVersion={currentVersion}
|
150
|
+
latestVersion={latestVersion}
|
151
|
+
localVersion={localVersion}
|
152
|
+
overrideVersionHref={overrideVersionHref}
|
153
|
+
showVersionDetails={showVersionDetails}
|
154
|
+
currentLane={currentLane}
|
155
|
+
getActiveTabIndex={getActiveTabIndex}
|
156
|
+
lanes={lanes}
|
157
|
+
useVersions={useComponentVersions}
|
158
|
+
onVersionClicked={() => setOpen(false)}
|
159
|
+
open={open}
|
160
|
+
/>
|
161
|
+
</Dropdown>
|
162
|
+
</div>
|
163
|
+
);
|
164
|
+
}
|
165
|
+
|
166
|
+
type VersionMenuProps = {
|
167
|
+
localVersion?: boolean;
|
168
|
+
currentVersion?: string;
|
169
|
+
latestVersion?: string;
|
170
|
+
useVersions?: UseComponentDropdownVersions;
|
171
|
+
currentLane?: LaneModel;
|
172
|
+
lanes?: LaneModel[];
|
173
|
+
overrideVersionHref?: (version: string) => string;
|
174
|
+
showVersionDetails?: boolean;
|
175
|
+
loading?: boolean;
|
176
|
+
getActiveTabIndex?: GetActiveTabIndex;
|
177
|
+
open?: boolean;
|
178
|
+
onVersionClicked?: () => void;
|
179
|
+
} & React.HTMLAttributes<HTMLDivElement>;
|
180
|
+
|
181
|
+
export type VersionMenuTab =
|
182
|
+
| {
|
183
|
+
name: 'SNAP';
|
184
|
+
payload: DropdownComponentVersion[];
|
185
|
+
}
|
186
|
+
| {
|
187
|
+
name: 'LANE';
|
188
|
+
payload: LaneModel[];
|
189
|
+
}
|
190
|
+
| {
|
191
|
+
name: 'TAG';
|
192
|
+
payload: DropdownComponentVersion[];
|
193
|
+
};
|
194
|
+
|
195
|
+
const defaultActiveTabIndex: GetActiveTabIndex = (currentVersion, tabs = [], tags, snaps) => {
|
196
|
+
if ((snaps || []).some((snap) => snap.version === currentVersion))
|
197
|
+
return tabs.findIndex((tab) => tab.name === 'SNAP');
|
198
|
+
return 0;
|
199
|
+
};
|
200
|
+
|
201
|
+
const VERSION_TAB_NAMES = ['TAG', 'SNAP', 'LANE'] as const;
|
202
|
+
function _VersionMenu({
|
203
|
+
currentVersion,
|
204
|
+
localVersion,
|
205
|
+
latestVersion,
|
206
|
+
overrideVersionHref,
|
207
|
+
showVersionDetails,
|
208
|
+
useVersions,
|
209
|
+
currentLane,
|
210
|
+
lanes,
|
211
|
+
getActiveTabIndex = defaultActiveTabIndex,
|
212
|
+
loading: loadingFromProps,
|
213
|
+
open,
|
214
|
+
onVersionClicked,
|
215
|
+
...rest
|
216
|
+
}: VersionMenuProps) {
|
217
|
+
const { snaps, tags, loading: loadingVersions } = useVersions?.() || {};
|
218
|
+
const loading = loadingFromProps || loadingVersions;
|
219
|
+
|
220
|
+
const tabs = React.useMemo(
|
221
|
+
() =>
|
222
|
+
VERSION_TAB_NAMES.map((name) => {
|
223
|
+
switch (name) {
|
224
|
+
case 'SNAP':
|
225
|
+
return { name, payload: snaps || [] };
|
226
|
+
case 'LANE':
|
227
|
+
return { name, payload: lanes || [] };
|
228
|
+
default:
|
229
|
+
return { name, payload: tags || [] };
|
230
|
+
}
|
231
|
+
}).filter((tab) => tab.payload.length > 0),
|
232
|
+
[snaps?.length, tags?.length, lanes?.length, loading]
|
233
|
+
);
|
234
|
+
|
235
|
+
const [activeTabIndex, setActiveTab] = React.useState<number | undefined>(
|
236
|
+
getActiveTabIndex(currentVersion, tabs, tags, snaps, currentLane)
|
237
|
+
);
|
238
|
+
|
239
|
+
const activeTab = React.useMemo(
|
240
|
+
() => (activeTabIndex !== undefined ? tabs[activeTabIndex] : undefined),
|
241
|
+
[activeTabIndex, tabs]
|
242
|
+
);
|
243
|
+
|
244
|
+
React.useEffect(() => {
|
245
|
+
if (!currentLane) return;
|
246
|
+
if (tabs.length === 0) return;
|
247
|
+
const _activeTabIndex = getActiveTabIndex(currentVersion, tabs, tags, snaps, currentLane);
|
248
|
+
if (_activeTabIndex !== activeTabIndex) setActiveTab(_activeTabIndex);
|
249
|
+
}, [currentLane, tabs.length, tags?.length, snaps?.length, currentVersion, loading]);
|
250
|
+
|
251
|
+
const multipleTabs = tabs.length > 1;
|
252
|
+
const message = multipleTabs
|
253
|
+
? 'Switch to view tags, snaps, or lanes'
|
254
|
+
: `Switch between ${tabs[0]?.name.toLocaleLowerCase()}s`;
|
255
|
+
|
256
|
+
const showTab = activeTabIndex !== undefined && tabs[activeTabIndex]?.payload.length > 0;
|
257
|
+
|
258
|
+
const _rowRenderer = React.useCallback(
|
259
|
+
function VersionRowRenderer({ index }) {
|
260
|
+
const { name, payload = [] } = activeTab || {};
|
261
|
+
const item = payload[index];
|
262
|
+
if (!item) return null;
|
263
|
+
if (name === 'LANE') {
|
264
|
+
const lane = item as LaneModel;
|
265
|
+
return <LaneInfo key={lane.id.toString()} currentLane={currentLane} {...lane}></LaneInfo>;
|
266
|
+
}
|
267
|
+
const version = item as DropdownComponentVersion;
|
268
|
+
return (
|
269
|
+
<VersionInfo
|
270
|
+
key={version.version}
|
271
|
+
currentVersion={currentVersion}
|
272
|
+
latestVersion={latestVersion}
|
273
|
+
overrideVersionHref={overrideVersionHref}
|
274
|
+
showDetails={showVersionDetails}
|
275
|
+
onVersionClicked={onVersionClicked}
|
276
|
+
{...version}
|
277
|
+
></VersionInfo>
|
278
|
+
);
|
279
|
+
},
|
280
|
+
[activeTab, currentVersion, latestVersion, showVersionDetails, currentLane?.id.toString(), showTab]
|
281
|
+
);
|
282
|
+
|
283
|
+
const rowRenderer = React.useMemo(
|
284
|
+
() => (showTab && activeTab ? _rowRenderer : () => null),
|
285
|
+
[showTab, activeTab, _rowRenderer]
|
286
|
+
);
|
287
|
+
|
288
|
+
const ActiveTab = React.useMemo(() => {
|
289
|
+
return activeTab?.payload.map((payload, index) => {
|
290
|
+
return rowRenderer({ index });
|
291
|
+
});
|
292
|
+
}, [activeTab]);
|
293
|
+
|
294
|
+
return (
|
295
|
+
<div {...rest} className={classNames(styles.versionMenuContainer, !open && styles.hide)}>
|
296
|
+
<div className={styles.top}>
|
297
|
+
{loading && <LineSkeleton count={6} className={styles.loader} />}
|
298
|
+
{!loading && <div className={classNames(styles.titleContainer, styles.title)}>{message}</div>}
|
299
|
+
{!loading && localVersion && (
|
300
|
+
<MenuLinkItem
|
301
|
+
href={'?'}
|
302
|
+
active={currentVersion === LOCAL_VERSION}
|
303
|
+
className={classNames(styles.versionRow, styles.localVersion)}
|
304
|
+
onClick={onVersionClicked}
|
305
|
+
>
|
306
|
+
<div className={styles.version}>
|
307
|
+
<UserAvatar size={24} account={{}} className={styles.versionUserAvatar} />
|
308
|
+
<span className={styles.versionName}>{LOCAL_VERSION}</span>
|
309
|
+
</div>
|
310
|
+
</MenuLinkItem>
|
311
|
+
)}
|
312
|
+
</div>
|
313
|
+
<div className={classNames(multipleTabs && styles.tabs)}>
|
314
|
+
{multipleTabs &&
|
315
|
+
tabs.map(({ name }, index) => {
|
316
|
+
return (
|
317
|
+
<Tab
|
318
|
+
className={styles.tab}
|
319
|
+
key={name}
|
320
|
+
isActive={activeTabIndex === index}
|
321
|
+
onClick={() => setActiveTab(index)}
|
322
|
+
>
|
323
|
+
{name}
|
324
|
+
</Tab>
|
325
|
+
);
|
326
|
+
})}
|
327
|
+
</div>
|
328
|
+
<div className={styles.versionContainerRoot}>{ActiveTab}</div>
|
329
|
+
</div>
|
330
|
+
);
|
331
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
.versionRow {
|
2
|
+
display: flex;
|
3
|
+
justify-content: space-between;
|
4
|
+
align-items: center;
|
5
|
+
height: 40px;
|
6
|
+
padding: 0 16px;
|
7
|
+
line-height: 1.2em;
|
8
|
+
|
9
|
+
&:hover {
|
10
|
+
background-color: var(--surface-hover-color, #eceaff) !important;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
.versionTimestamp {
|
15
|
+
min-width: fit-content;
|
16
|
+
margin-right: 2px;
|
17
|
+
text-align: right;
|
18
|
+
}
|
19
|
+
|
20
|
+
.versionUserAvatar {
|
21
|
+
flex: none;
|
22
|
+
padding: 0px 8px;
|
23
|
+
}
|
24
|
+
|
25
|
+
.laneIcon {
|
26
|
+
padding: 0px 4px;
|
27
|
+
}
|
28
|
+
|
29
|
+
.version {
|
30
|
+
max-width: 70%;
|
31
|
+
display: flex;
|
32
|
+
flex-direction: row;
|
33
|
+
align-items: center;
|
34
|
+
justify-content: flex-start;
|
35
|
+
overflow: hidden;
|
36
|
+
}
|
37
|
+
|
38
|
+
.versionName {
|
39
|
+
padding: 0px 8px;
|
40
|
+
flex-grow: 1;
|
41
|
+
min-width: fit-content;
|
42
|
+
}
|
43
|
+
|
44
|
+
.commitMessage {
|
45
|
+
flex-grow: 1;
|
46
|
+
padding: 0px 8px;
|
47
|
+
}
|
48
|
+
|
49
|
+
.emptyMessage {
|
50
|
+
font-style: italic;
|
51
|
+
color: var(--bit-text-color-light, #6c707c);
|
52
|
+
padding: 0px 8px;
|
53
|
+
font-size: (var-bit-p-xs, 14px);
|
54
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import { MenuLinkItem } from '@teambit/design.ui.surfaces.menu.link-item';
|
2
|
+
import { TimeAgo } from '@teambit/design.ui.time-ago';
|
3
|
+
import { VersionLabel } from '@teambit/component.ui.version-label';
|
4
|
+
import React, { useMemo, useRef, useEffect } from 'react';
|
5
|
+
import { UserAvatar } from '@teambit/design.ui.avatar';
|
6
|
+
import { Ellipsis } from '@teambit/design.ui.styles.ellipsis';
|
7
|
+
import classNames from 'classnames';
|
8
|
+
|
9
|
+
import type { DropdownComponentVersion } from '../version-dropdown';
|
10
|
+
import styles from './version-info.module.scss';
|
11
|
+
|
12
|
+
export interface VersionInfoProps extends DropdownComponentVersion {
|
13
|
+
currentVersion?: string;
|
14
|
+
latestVersion?: string;
|
15
|
+
overrideVersionHref?: (version: string) => string;
|
16
|
+
showDetails?: boolean;
|
17
|
+
onVersionClicked?: () => void;
|
18
|
+
}
|
19
|
+
|
20
|
+
export const VersionInfo = React.memo(React.forwardRef<HTMLDivElement, VersionInfoProps>(_VersionInfo));
|
21
|
+
function _VersionInfo(
|
22
|
+
{
|
23
|
+
version,
|
24
|
+
currentVersion,
|
25
|
+
latestVersion,
|
26
|
+
date,
|
27
|
+
username,
|
28
|
+
displayName,
|
29
|
+
email,
|
30
|
+
overrideVersionHref,
|
31
|
+
showDetails,
|
32
|
+
message,
|
33
|
+
tag,
|
34
|
+
profileImage,
|
35
|
+
onVersionClicked,
|
36
|
+
}: VersionInfoProps,
|
37
|
+
ref?: React.ForwardedRef<HTMLDivElement>
|
38
|
+
) {
|
39
|
+
const isCurrent = version === currentVersion;
|
40
|
+
const author = useMemo(() => {
|
41
|
+
return {
|
42
|
+
displayName: displayName ?? '',
|
43
|
+
email,
|
44
|
+
name: username ?? '',
|
45
|
+
profileImage,
|
46
|
+
};
|
47
|
+
}, [displayName, email, username, profileImage]);
|
48
|
+
|
49
|
+
const timestamp = useMemo(() => (date ? new Date(parseInt(date)).toString() : new Date().toString()), [date]);
|
50
|
+
const currentVersionRef = useRef<HTMLDivElement>(null);
|
51
|
+
|
52
|
+
useEffect(() => {
|
53
|
+
if (isCurrent) {
|
54
|
+
currentVersionRef.current?.scrollIntoView({ block: 'nearest' });
|
55
|
+
}
|
56
|
+
}, [isCurrent]);
|
57
|
+
|
58
|
+
const href = overrideVersionHref ? overrideVersionHref(version) : `?version=${version}`;
|
59
|
+
|
60
|
+
const formattedVersion = useMemo(() => {
|
61
|
+
return tag ? version : version.slice(0, 6);
|
62
|
+
}, [tag, version]);
|
63
|
+
|
64
|
+
const isLatest = version === latestVersion;
|
65
|
+
|
66
|
+
return (
|
67
|
+
<div ref={ref || currentVersionRef} onClick={onVersionClicked}>
|
68
|
+
<MenuLinkItem active={isCurrent} href={href} className={styles.versionRow}>
|
69
|
+
<div className={styles.version}>
|
70
|
+
<UserAvatar size={24} account={author} className={styles.versionUserAvatar} showTooltip={true} />
|
71
|
+
<Ellipsis className={classNames(styles.versionName)}>{formattedVersion}</Ellipsis>
|
72
|
+
{isLatest && <VersionLabel status="latest" />}
|
73
|
+
<CommitMessage message={message} showDetails={showDetails} />
|
74
|
+
</div>
|
75
|
+
<Ellipsis className={styles.versionTimestamp}>
|
76
|
+
<TimeAgo date={timestamp} />
|
77
|
+
</Ellipsis>
|
78
|
+
</MenuLinkItem>
|
79
|
+
</div>
|
80
|
+
);
|
81
|
+
}
|
82
|
+
|
83
|
+
function CommitMessage({ message, showDetails }: { message?: string; showDetails?: boolean }) {
|
84
|
+
if (!showDetails) return null;
|
85
|
+
if (!message || message === '') return <Ellipsis className={styles.emptyMessage}>No commit message</Ellipsis>;
|
86
|
+
return <Ellipsis className={styles.commitMessage}>{message}</Ellipsis>;
|
87
|
+
}
|