Skip to content

Commit 4609ba9

Browse files
committed
fix: license text modified overlaps license name
- always show license text input - display default license text as placeholder when a default license name is selected closes #2529 Signed-off-by: Maxim Stykow <maxim.stykow@tngtech.com>
1 parent 12a723d commit 4609ba9

File tree

9 files changed

+103
-201
lines changed

9 files changed

+103
-201
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

+52-131
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,24 @@
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';
116
import { sortBy } from 'lodash';
12-
import { useMemo, useState } from 'react';
7+
import { useMemo } from 'react';
138

149
import { PackageInfo } from '../../../../shared/shared-types';
1510
import { text } from '../../../../shared/text';
1611
import { setTemporaryDisplayPackageInfo } from '../../../state/actions/resource-actions/all-views-simple-actions';
1712
import { useAppDispatch, useAppSelector } from '../../../state/hooks';
18-
import { getFrequentLicensesNameOrder } from '../../../state/selectors/resource-selectors';
13+
import {
14+
getFrequentLicensesNameOrder,
15+
getFrequentLicensesTexts,
16+
} from '../../../state/selectors/resource-selectors';
1917
import { Confirm } from '../../ConfirmationDialog/ConfirmationDialog';
2018
import { TextBox } from '../../TextBox/TextBox';
2119
import { AttributionFormConfig } from '../AttributionForm';
22-
import { attributionColumnClasses } from '../AttributionForm.style';
2320
import { PackageAutocomplete } from '../PackageAutocomplete/PackageAutocomplete';
2421

2522
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-
},
5723
licenseText: {
5824
marginTop: '12px',
5925
},
@@ -76,12 +42,12 @@ export function LicenseSubPanel({
7642
packageInfo,
7743
showHighlight,
7844
onEdit,
79-
expanded: expandedOverride,
45+
expanded,
8046
hidden,
8147
config,
8248
}: LicenseSubPanelProps) {
8349
const dispatch = useAppDispatch();
84-
const [expanded, setExpanded] = useState(expandedOverride);
50+
const frequentLicenseTexts = useAppSelector(getFrequentLicensesTexts);
8551
const frequentLicensesNames = useAppSelector(getFrequentLicensesNameOrder);
8652
const defaultLicenses = useMemo(
8753
() =>
@@ -98,99 +64,54 @@ export function LicenseSubPanel({
9864
),
9965
[frequentLicensesNames],
10066
);
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-
);
67+
68+
const defaultLicenseText = packageInfo.licenseText
69+
? undefined
70+
: frequentLicenseTexts[packageInfo.licenseName || ''];
11771

11872
return hidden ? null : (
119-
<MuiBox sx={classes.panel}>
120-
<MuiAccordion
121-
sx={classes.expansionPanel}
122-
elevation={0}
123-
key={'License'}
124-
disableGutters
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+
<TextBox
87+
readOnly={!onEdit}
88+
placeholder={defaultLicenseText}
89+
sx={classes.licenseText}
90+
maxRows={8}
91+
minRows={3}
92+
color={config?.licenseText?.color}
93+
focused={config?.licenseText?.focused}
94+
multiline
12595
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>
138-
)
139-
}
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>
96+
title={
97+
defaultLicenseText
98+
? text.attributionColumn.licenseTextDefault
99+
: text.attributionColumn.licenseText
100+
}
101+
text={packageInfo.licenseText}
102+
handleChange={({ target: { value } }) =>
103+
onEdit?.(() =>
104+
dispatch(
105+
setTemporaryDisplayPackageInfo({
106+
...packageInfo,
107+
licenseText: value,
108+
wasPreferred: undefined,
109+
}),
110+
),
111+
)
112+
}
113+
endIcon={config?.licenseText?.endIcon}
114+
/>
194115
</MuiBox>
195116
);
196117
}

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

+40-43
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
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';
1212
import { setFrequentLicenses } from '../../../state/actions/resource-actions/all-views-simple-actions';
13-
import { setSelectedAttributionId } from '../../../state/actions/resource-actions/audit-view-simple-actions';
1413
import { getTemporaryDisplayPackageInfo } from '../../../state/selectors/resource-selectors';
1514
import { renderComponent } from '../../../test-helpers/render';
1615
import { generatePurl } from '../../../util/handle-purl';
@@ -201,63 +200,61 @@ describe('AttributionForm', () => {
201200
expect(screen.queryByLabelText('Url icon')).not.toBeInTheDocument();
202201
});
203202

204-
it('shows standard text if editable and non frequent license', () => {
205-
const packageInfo: PackageInfo = {
206-
packageName: 'jQuery',
207-
id: faker.string.uuid(),
208-
};
203+
it('shows default license text placeholder when frequent license name selected and no custom license text entered', () => {
204+
const defaultLicenseText = faker.lorem.paragraphs();
205+
const packageInfo = faker.opossum.packageInfo();
209206
renderComponent(
210207
<AttributionForm packageInfo={packageInfo} onEdit={jest.fn()} />,
208+
{
209+
actions: [
210+
setFrequentLicenses({
211+
nameOrder: [],
212+
texts: { [packageInfo.licenseName!]: defaultLicenseText },
213+
}),
214+
],
215+
},
211216
);
212217

213218
expect(
214-
screen.getByLabelText('License Text (to appear in attribution document)'),
215-
).toBeInTheDocument();
216-
});
217-
218-
it('shows shortened text if not editable and frequent license', () => {
219-
const packageInfo: PackageInfo = {
220-
packageName: 'jQuery',
221-
licenseName: 'Mit',
222-
id: faker.string.uuid(),
223-
};
224-
const frequentLicenses: FrequentLicenses = {
225-
nameOrder: [{ shortName: 'MIT', fullName: 'MIT license' }],
226-
texts: { MIT: 'text' },
227-
};
228-
renderComponent(<AttributionForm packageInfo={packageInfo} />, {
229-
actions: [
230-
setFrequentLicenses(frequentLicenses),
231-
setSelectedAttributionId(packageInfo.id),
232-
],
233-
});
234-
219+
screen.getByRole('textbox', {
220+
name: text.attributionColumn.licenseTextDefault,
221+
}),
222+
).toHaveAttribute('placeholder', defaultLicenseText);
235223
expect(
236-
screen.getByLabelText('Standard license text implied.'),
224+
screen.getByLabelText(text.attributionColumn.licenseTextDefault),
237225
).toBeInTheDocument();
226+
expect(
227+
screen.queryByLabelText(text.attributionColumn.licenseText),
228+
).not.toBeInTheDocument();
238229
});
239230

240-
it('shows long text if editable and frequent license', () => {
241-
const packageInfo: PackageInfo = {
242-
packageName: 'jQuery',
243-
licenseName: 'mit',
244-
id: faker.string.uuid(),
245-
};
246-
const frequentLicenses: FrequentLicenses = {
247-
nameOrder: [{ shortName: 'MIT', fullName: 'MIT license' }],
248-
texts: { MIT: 'text' },
249-
};
231+
it('does not show default license text placeholder when custom license text entered', () => {
232+
const defaultLicenseText = faker.lorem.paragraphs();
233+
const packageInfo = faker.opossum.packageInfo({
234+
licenseText: faker.lorem.paragraphs(),
235+
});
250236
renderComponent(
251237
<AttributionForm packageInfo={packageInfo} onEdit={jest.fn()} />,
252238
{
253-
actions: [setFrequentLicenses(frequentLicenses)],
239+
actions: [
240+
setFrequentLicenses({
241+
nameOrder: [],
242+
texts: { [packageInfo.licenseName!]: defaultLicenseText },
243+
}),
244+
],
254245
},
255246
);
256247

257248
expect(
258-
screen.getByLabelText(
259-
'Standard license text implied. Insert notice text if necessary.',
260-
),
249+
screen.getByRole('textbox', {
250+
name: text.attributionColumn.licenseText,
251+
}),
252+
).not.toHaveAttribute('placeholder', defaultLicenseText);
253+
expect(
254+
screen.queryByLabelText(text.attributionColumn.licenseTextDefault),
255+
).not.toBeInTheDocument();
256+
expect(
257+
screen.getByLabelText(text.attributionColumn.licenseText),
261258
).toBeInTheDocument();
262259
});
263260

src/Frontend/Components/TextBox/TextBox.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export const classes = {
5757

5858
export interface TextBoxProps {
5959
color?: TextFieldProps['color'];
60+
placeholder?: string;
6061
disabled?: boolean;
6162
expanded?: boolean;
6263
focused?: boolean;
@@ -70,7 +71,7 @@ export interface TextBoxProps {
7071
readOnly?: boolean;
7172
sx?: SxProps;
7273
text?: string;
73-
title?: string;
74+
title: string;
7475
endIcon?: React.ReactElement | Array<React.ReactElement>;
7576
}
7677

@@ -79,13 +80,17 @@ export function TextBox(props: TextBoxProps) {
7980
<MuiBox sx={props.sx}>
8081
<MuiTextField
8182
disabled={props.disabled}
83+
placeholder={props.placeholder}
8284
sx={{
8385
...classes.textField,
8486
...(props.error && classes.defaultHighlightedTextField),
8587
}}
8688
label={props.title}
8789
focused={props.focused}
8890
color={props.color}
91+
InputLabelProps={{
92+
shrink: !!props.placeholder || !!props.text,
93+
}}
8994
InputProps={{
9095
readOnly: props.readOnly,
9196
slotProps: { root: { sx: { padding: 0 } } },

0 commit comments

Comments
 (0)