Skip to content

Commit 133c4dc

Browse files
committed
fix: license text modified overlaps license name
- always show license text input if license text exists - show button with explanatory tooltip to specify a custom license text when no license text present - this button enables user to specify a license text when needed but hides the input in most cases closes #2529 Signed-off-by: Maxim Stykow <maxim.stykow@tngtech.com>
1 parent 66cccae commit 133c4dc

File tree

9 files changed

+125
-179
lines changed

9 files changed

+125
-179
lines changed

src/Frontend/Components/AttributionForm/Comment/Comment.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export function Comment({ packageInfo, onEdit, config, expanded }: Props) {
2929
title={'Comment'}
3030
text={packageInfo.comment}
3131
minRows={3}
32-
maxRows={10}
32+
maxRows={5}
3333
multiline={true}
3434
color={config?.color}
3535
focused={config?.focused}

src/Frontend/Components/AttributionForm/CopyrightSubPanel/CopyrightSubPanel.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function CopyrightSubPanel({
4040
title={'Copyright'}
4141
text={packageInfo.copyright}
4242
minRows={3}
43-
maxRows={7}
43+
maxRows={5}
4444
color={config?.color}
4545
focused={config?.focused}
4646
multiline

src/Frontend/Components/AttributionForm/LicenseSubPanel/LicenseSubPanel.tsx

+61-129
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@
22
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
33
//
44
// SPDX-License-Identifier: Apache-2.0
5-
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
6-
import MuiAccordion from '@mui/material/Accordion';
7-
import MuiAccordionDetails from '@mui/material/AccordionDetails';
8-
import MuiAccordionSummary from '@mui/material/AccordionSummary';
95
import MuiBox from '@mui/material/Box';
10-
import MuiInputAdornment from '@mui/material/InputAdornment';
6+
import Link from '@mui/material/Link';
7+
import Tooltip from '@mui/material/Tooltip';
118
import { sortBy } from 'lodash';
12-
import { useMemo, useState } from 'react';
9+
import { useEffect, useMemo, useState } from 'react';
1310

1411
import { PackageInfo } from '../../../../shared/shared-types';
1512
import { text } from '../../../../shared/text';
@@ -19,41 +16,9 @@ import { getFrequentLicensesNameOrder } from '../../../state/selectors/resource-
1916
import { Confirm } from '../../ConfirmationDialog/ConfirmationDialog';
2017
import { TextBox } from '../../TextBox/TextBox';
2118
import { AttributionFormConfig } from '../AttributionForm';
22-
import { attributionColumnClasses } from '../AttributionForm.style';
2319
import { PackageAutocomplete } from '../PackageAutocomplete/PackageAutocomplete';
2420

2521
const classes = {
26-
...attributionColumnClasses,
27-
expansionPanel: {
28-
backgroundColor: 'transparent',
29-
'&.MuiAccordion-expanded': {
30-
margin: '0px 0px 6px 0px !important',
31-
},
32-
},
33-
expansionPanelSummary: {
34-
minHeight: '36px',
35-
padding: '0px',
36-
'& div.MuiAccordionSummary-content': {
37-
margin: '0px',
38-
},
39-
'& div.MuiAccordionSummary-expandIcon': {
40-
padding: '0px',
41-
},
42-
},
43-
expansionPanelDetails: {
44-
padding: '0px',
45-
width: 'calc(100% - 36px)',
46-
},
47-
expansionPanelDetailsDiffView: {
48-
padding: '0px',
49-
},
50-
expandMoreIcon: {
51-
display: 'flex',
52-
alignItems: 'center',
53-
justifyContent: 'center',
54-
height: '36px',
55-
width: '36px',
56-
},
5722
licenseText: {
5823
marginTop: '12px',
5924
},
@@ -76,12 +41,12 @@ export function LicenseSubPanel({
7641
packageInfo,
7742
showHighlight,
7843
onEdit,
79-
expanded: expandedOverride,
44+
expanded,
8045
hidden,
8146
config,
8247
}: LicenseSubPanelProps) {
8348
const dispatch = useAppDispatch();
84-
const [expanded, setExpanded] = useState(expandedOverride);
49+
const [isLicenseTextShown, setIsLicenseTextShown] = useState(false);
8550
const frequentLicensesNames = useAppSelector(getFrequentLicensesNameOrder);
8651
const defaultLicenses = useMemo(
8752
() =>
@@ -98,99 +63,66 @@ export function LicenseSubPanel({
9863
),
9964
[frequentLicensesNames],
10065
);
101-
const label = useMemo(
102-
() =>
103-
packageInfo.licenseName &&
104-
frequentLicensesNames
105-
.map((licenseNames) => [
106-
licenseNames.shortName.toLowerCase(),
107-
licenseNames.fullName.toLowerCase(),
108-
])
109-
.flat()
110-
.includes(packageInfo.licenseName.toLowerCase())
111-
? `Standard license text implied. ${
112-
!!onEdit ? 'Insert notice text if necessary.' : ''
113-
}`
114-
: 'License Text (to appear in attribution document)',
115-
[frequentLicensesNames, onEdit, packageInfo.licenseName],
116-
);
66+
const showLicenseTextInput = expanded || !!packageInfo.licenseText;
67+
68+
useEffect(() => {
69+
setIsLicenseTextShown(showLicenseTextInput);
70+
}, [showLicenseTextInput]);
11771

11872
return hidden ? null : (
119-
<MuiBox sx={classes.panel}>
120-
<MuiAccordion
121-
sx={classes.expansionPanel}
122-
elevation={0}
123-
key={'License'}
124-
disableGutters
125-
expanded={expanded}
126-
square
127-
>
128-
<MuiAccordionSummary
129-
sx={classes.expansionPanelSummary}
130-
expandIcon={
131-
expandedOverride ? null : (
132-
<MuiBox
133-
sx={classes.expandMoreIcon}
134-
onClick={() => setExpanded((prev) => !prev)}
135-
>
136-
<ExpandMoreIcon aria-label={'license text toggle'} />
137-
</MuiBox>
73+
<MuiBox>
74+
<PackageAutocomplete
75+
attribute={'licenseName'}
76+
title={text.attributionColumn.licenseName}
77+
packageInfo={packageInfo}
78+
readOnly={!onEdit}
79+
showHighlight={showHighlight}
80+
onEdit={onEdit}
81+
endAdornment={config?.licenseName?.endIcon}
82+
defaults={defaultLicenses}
83+
color={config?.licenseName?.color}
84+
focused={config?.licenseName?.focused}
85+
/>
86+
{isLicenseTextShown ? (
87+
<TextBox
88+
readOnly={!onEdit}
89+
sx={classes.licenseText}
90+
maxRows={10}
91+
minRows={3}
92+
color={config?.licenseText?.color}
93+
focused={config?.licenseText?.focused}
94+
multiline
95+
expanded={expanded}
96+
title={text.attributionColumn.licenseText}
97+
text={packageInfo.licenseText}
98+
handleChange={({ target: { value } }) =>
99+
onEdit?.(() =>
100+
dispatch(
101+
setTemporaryDisplayPackageInfo({
102+
...packageInfo,
103+
licenseText: value,
104+
wasPreferred: undefined,
105+
}),
106+
),
138107
)
139108
}
140-
>
141-
<PackageAutocomplete
142-
attribute={'licenseName'}
143-
title={text.attributionColumn.licenseName}
144-
packageInfo={packageInfo}
145-
readOnly={!onEdit}
146-
showHighlight={showHighlight}
147-
onEdit={onEdit}
148-
endAdornment={
149-
config?.licenseName?.endIcon ||
150-
(packageInfo.licenseText ? (
151-
<MuiInputAdornment position="end" sx={classes.endAdornment}>
152-
{text.attributionColumn.licenseTextModified}
153-
</MuiInputAdornment>
154-
) : undefined)
155-
}
156-
defaults={defaultLicenses}
157-
color={config?.licenseName?.color}
158-
focused={config?.licenseName?.focused}
159-
/>
160-
</MuiAccordionSummary>
161-
<MuiAccordionDetails
162-
sx={
163-
expandedOverride
164-
? classes.expansionPanelDetailsDiffView
165-
: classes.expansionPanelDetails
166-
}
167-
>
168-
<TextBox
169-
readOnly={!onEdit}
170-
sx={classes.licenseText}
171-
maxRows={7}
172-
minRows={3}
173-
color={config?.licenseText?.color}
174-
focused={config?.licenseText?.focused}
175-
multiline
176-
expanded={expandedOverride}
177-
title={label}
178-
text={packageInfo.licenseText}
179-
handleChange={({ target: { value } }) =>
180-
onEdit?.(() =>
181-
dispatch(
182-
setTemporaryDisplayPackageInfo({
183-
...packageInfo,
184-
licenseText: value,
185-
wasPreferred: undefined,
186-
}),
187-
),
188-
)
189-
}
190-
endIcon={config?.licenseText?.endIcon}
191-
/>
192-
</MuiAccordionDetails>
193-
</MuiAccordion>
109+
endIcon={config?.licenseText?.endIcon}
110+
/>
111+
) : (
112+
onEdit && (
113+
<Tooltip title={text.attributionColumn.useCustomLicenseTextHint}>
114+
<Link
115+
sx={{ padding: '4px' }}
116+
underline={'hover'}
117+
component={'button'}
118+
variant={'caption'}
119+
onClick={() => setIsLicenseTextShown(true)}
120+
>
121+
{text.attributionColumn.useCustomLicenseText}
122+
</Link>
123+
</Tooltip>
124+
)
125+
)}
194126
</MuiBox>
195127
);
196128
}

src/Frontend/Components/AttributionForm/__tests__/AttributionForm.test.tsx

+45-29
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
import { fireEvent, screen } from '@testing-library/react';
77
import userEvent from '@testing-library/user-event';
88

9-
import { FrequentLicenses, PackageInfo } from '../../../../shared/shared-types';
9+
import { PackageInfo } from '../../../../shared/shared-types';
1010
import { text } from '../../../../shared/text';
1111
import { faker } from '../../../../testing/Faker';
12-
import { setFrequentLicenses } from '../../../state/actions/resource-actions/all-views-simple-actions';
13-
import { setSelectedAttributionId } from '../../../state/actions/resource-actions/audit-view-simple-actions';
1412
import { getTemporaryDisplayPackageInfo } from '../../../state/selectors/resource-selectors';
1513
import { renderComponent } from '../../../test-helpers/render';
1614
import { generatePurl } from '../../../util/handle-purl';
@@ -201,7 +199,7 @@ describe('AttributionForm', () => {
201199
expect(screen.queryByLabelText('Url icon')).not.toBeInTheDocument();
202200
});
203201

204-
it('shows standard text if editable and non frequent license', () => {
202+
it('shows button to use custom license text if no license text specified and in edit mode', () => {
205203
const packageInfo: PackageInfo = {
206204
packageName: 'jQuery',
207205
id: faker.string.uuid(),
@@ -211,53 +209,71 @@ describe('AttributionForm', () => {
211209
);
212210

213211
expect(
214-
screen.getByLabelText('License Text (to appear in attribution document)'),
212+
screen.getByRole('button', {
213+
name: text.attributionColumn.useCustomLicenseTextHint,
214+
}),
215215
).toBeInTheDocument();
216+
expect(
217+
screen.queryByLabelText(text.attributionColumn.licenseText),
218+
).not.toBeInTheDocument();
216219
});
217220

218-
it('shows shortened text if not editable and frequent license', () => {
221+
it('shows neither button to use custom license text nor license text input field if no license text specified but not in edit mode', () => {
219222
const packageInfo: PackageInfo = {
220223
packageName: 'jQuery',
221-
licenseName: 'Mit',
222224
id: faker.string.uuid(),
223225
};
224-
const frequentLicenses: FrequentLicenses = {
225-
nameOrder: [{ shortName: 'MIT', fullName: 'MIT license' }],
226-
texts: { MIT: 'text' },
226+
renderComponent(<AttributionForm packageInfo={packageInfo} />);
227+
228+
expect(
229+
screen.queryByRole('button', {
230+
name: text.attributionColumn.useCustomLicenseTextHint,
231+
}),
232+
).not.toBeInTheDocument();
233+
expect(
234+
screen.queryByLabelText(text.attributionColumn.licenseText),
235+
).not.toBeInTheDocument();
236+
});
237+
238+
it('shows license text instead of button if license text is specified and in edit mode', () => {
239+
const licenseText = faker.lorem.paragraph();
240+
const packageInfo: PackageInfo = {
241+
packageName: 'jQuery',
242+
id: faker.string.uuid(),
243+
licenseText,
227244
};
228-
renderComponent(<AttributionForm packageInfo={packageInfo} />, {
229-
actions: [
230-
setFrequentLicenses(frequentLicenses),
231-
setSelectedAttributionId(packageInfo.id),
232-
],
233-
});
245+
renderComponent(
246+
<AttributionForm packageInfo={packageInfo} onEdit={jest.fn()} />,
247+
);
234248

235249
expect(
236-
screen.getByLabelText('Standard license text implied.'),
250+
screen.getByLabelText(text.attributionColumn.licenseText),
237251
).toBeInTheDocument();
252+
expect(screen.getByDisplayValue(licenseText)).toBeInTheDocument();
253+
expect(
254+
screen.queryByRole('button', {
255+
name: text.attributionColumn.useCustomLicenseTextHint,
256+
}),
257+
).not.toBeInTheDocument();
238258
});
239259

240-
it('shows long text if editable and frequent license', () => {
260+
it('shows license text input field when user clicks button to use custom license text', async () => {
241261
const packageInfo: PackageInfo = {
242262
packageName: 'jQuery',
243-
licenseName: 'mit',
244263
id: faker.string.uuid(),
245264
};
246-
const frequentLicenses: FrequentLicenses = {
247-
nameOrder: [{ shortName: 'MIT', fullName: 'MIT license' }],
248-
texts: { MIT: 'text' },
249-
};
250265
renderComponent(
251266
<AttributionForm packageInfo={packageInfo} onEdit={jest.fn()} />,
252-
{
253-
actions: [setFrequentLicenses(frequentLicenses)],
254-
},
267+
);
268+
269+
await userEvent.click(
270+
screen.getByRole('button', {
271+
name: text.attributionColumn.useCustomLicenseTextHint,
272+
}),
255273
);
256274

257275
expect(
258-
screen.getByLabelText(
259-
'Standard license text implied. Insert notice text if necessary.',
260-
),
276+
screen.getByLabelText(text.attributionColumn.licenseText),
261277
).toBeInTheDocument();
262278
});
263279

src/Frontend/Components/TextBox/TextBox.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export interface TextBoxProps {
7070
readOnly?: boolean;
7171
sx?: SxProps;
7272
text?: string;
73-
title?: string;
73+
title: string;
7474
endIcon?: React.ReactElement | Array<React.ReactElement>;
7575
}
7676

src/e2e-tests/__tests__/comparing-attribution-with-origin.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ test('reverts all changes and applies reverted state to temporary package info',
8080
AttributionType.FirstParty,
8181
);
8282
await diffPopup.currentAttributionForm.assert.copyrightIs('');
83-
await diffPopup.currentAttributionForm.assert.licenseTextIsVisible();
83+
await diffPopup.currentAttributionForm.assert.licenseTextInputIsVisible();
8484
await diffPopup.currentAttributionForm.assert.licenseTextIs('');
8585
await diffPopup.currentAttributionForm.assert.licenseNameIs('');
8686
await diffPopup.currentAttributionForm.assert.nameUndoButtonIsVisible();
@@ -168,7 +168,7 @@ test('handles pending license and copyright changes in temporary package info co
168168

169169
await diffPopup.currentAttributionForm.attributionTypeRedoButton.click();
170170
await diffPopup.applyButton.click();
171-
await attributionDetails.attributionForm.assert.licenseTextIsHidden();
171+
await attributionDetails.attributionForm.assert.licenseTextInputIsHidden();
172172

173173
await attributionDetails.attributionForm.selectAttributionType(
174174
AttributionType.ThirdParty,

0 commit comments

Comments
 (0)