Skip to content

Commit

Permalink
Merge branch 'main' into task/WP-32--onboarding-page-filter-incomplet…
Browse files Browse the repository at this point in the history
…e-users
  • Loading branch information
asimregmi authored Oct 25, 2023
2 parents f8f03ac + f3e7f18 commit 9cbec5c
Show file tree
Hide file tree
Showing 28 changed files with 518 additions and 286 deletions.
296 changes: 150 additions & 146 deletions client/package-lock.json

Large diffs are not rendered by default.

20 changes: 15 additions & 5 deletions client/src/components/Applications/AppForm/AppForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -692,11 +692,21 @@ export const AppSchemaForm = ({ app }) => {
)
.map((q) => q.name)
.sort()
.map((queueName) => (
<option key={queueName} value={queueName}>
{queueName}
</option>
))
.map((queueName) =>
app.definition.notes.queueFilter ? (
app.definition.notes.queueFilter.includes(
queueName
) && (
<option key={queueName} value={queueName}>
{queueName}
</option>
)
) : (
<option key={queueName} value={queueName}>
{queueName}
</option>
)
)
.sort()}
</FormField>
)}
Expand Down
55 changes: 55 additions & 0 deletions client/src/components/Applications/AppForm/AppForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,3 +442,58 @@ describe('AppDetail', () => {
).toBeDefined();
});
});

const mockAppWithQueueFilter = {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
notes: {
...helloWorldAppFixture.definition.notes,
queueFilter: ['rtx', 'small'],
},
},
};

const mockAppWithoutQueueFilter = {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
notes: {
...helloWorldAppFixture.definition.notes,
queueFilter: null,
},
},
};

describe('AppSchemaForm queueFilter tests', () => {
it('renders only the queues specified in the queueFilter', () => {
const { container } = renderAppSchemaFormComponent(
mockStore(initialMockState),
mockAppWithQueueFilter
);

const targetDropdown = container.querySelector(
'select[name="execSystemLogicalQueue"]'
);
const options = Array.from(targetDropdown.querySelectorAll('option'));
expect(options).toHaveLength(2);
expect(options[0].textContent).toBe('rtx');
expect(options[1].textContent).toBe('small');
});

it('renders all queues when no queueFilter is present', () => {
const { container } = renderAppSchemaFormComponent(
mockStore(initialMockState),
mockAppWithoutQueueFilter
);

const targetDropdown = container.querySelector(
'select[name="execSystemLogicalQueue"]'
);
const options = Array.from(targetDropdown.querySelectorAll('option'));
expect(options).toHaveLength(3);
expect(options[0].textContent).toBe('development');
expect(options[1].textContent).toBe('rtx');
expect(options[2].textContent).toBe('small');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ const DataFilesProjectMembers = ({
};

DataFilesProjectMembers.propTypes = {
projectId: PropTypes.string,
projectId: PropTypes.string.isRequired,
members: PropTypes.arrayOf(
PropTypes.shape({
username: PropTypes.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ function JobHistoryContent({
const outputDataObj = {
'Job Name': jobName,
'Output Location': outputLocation,
'Archive System': jobDetails.archiveSystemId,
'Archive Directory': jobDetails.archiveSystemDir,
};

const resubmitJob = () => {
Expand Down
49 changes: 34 additions & 15 deletions client/src/components/Jobs/Jobs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Link, useLocation } from 'react-router-dom';
import {
AppIcon,
InfiniteScrollTable,
HighlightSearchTerm,
Message,
SectionMessage,
Section,
Expand Down Expand Up @@ -90,8 +91,6 @@ function JobsView({
original: { id, uuid, name },
},
}) => {
const query = queryStringParser.parse(useLocation().search);

// TODOv3: dropV2Jobs
const jobsPathname = uuid ? `/jobs/${uuid}` : `/jobsv2/${id}`;
return (
Expand All @@ -105,11 +104,11 @@ function JobsView({
}}
className="wb-link"
>
View Details
{query.query_string ? <b>View Details</b> : 'View Details'}
</Link>
);
},
[]
[query]
);

if (error) {
Expand All @@ -133,15 +132,24 @@ function JobsView({
{
Header: 'Job Name',
accessor: 'name',
Cell: (el) => (
<span
title={el.value}
id={`jobID${el.row.index}`}
className="job__name"
>
{el.value}
</span>
),
Cell: (el) => {
return (
<span
title={el.value}
id={`jobID${el.row.index}`}
className="job__name"
>
{query.query_string ? (
<HighlightSearchTerm
searchTerm={query.query_string}
content={el.value}
/>
) : (
el.value
)}
</span>
);
},
},
{
Header: 'Job Status',
Expand Down Expand Up @@ -183,12 +191,20 @@ function JobsView({
// TODOv3: dropV2Jobs
if (el.row.original.uuid) {
const outputLocation = getOutputPath(el.row.original);

return outputLocation && !hideDataFiles ? (
<Link
to={`${ROUTES.WORKBENCH}${ROUTES.DATA}/tapis/private/${outputLocation}`}
className="wb-link job__path"
>
{outputLocation}
{query.query_string ? (
<HighlightSearchTerm
searchTerm={query.query_string}
content={outputLocation}
/>
) : (
outputLocation
)}
</Link>
) : null;
} else {
Expand Down Expand Up @@ -232,7 +248,10 @@ function JobsView({
</Section>
}
getRowProps={rowProps}
columnMemoProps={[version]} /* TODOv3: dropV2Jobs. */
columnMemoProps={[
version,
query,
]} /* TODOv3: dropV2Jobs. Refactor version prop. */
/>
</>
);
Expand Down
2 changes: 0 additions & 2 deletions client/src/components/ManageAccount/ManageAccountTables.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ export const ProfileInformation = () => {
{ Header: 'Institution', accessor: 'institution' },
{ Header: 'Country of Residence', accessor: 'country' },
{ Header: 'Country of Citizenship', accessor: 'citizenship' },
{ Header: 'Ethnicity', accessor: 'ethnicity' },
{ Header: 'Gender', accessor: 'gender' },
],
[]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ const dummyState = {
},
data: {
demographics: {
ethnicity: 'Asian',
gender: 'Male',
bio: '',
website: 'http://owais.io',
orcid_id: 'test',
professional_level: 'Staff (support, administration, etc)',
username: 'ojamil',
email: '[email protected]',
firstName: 'Owais',
Expand Down Expand Up @@ -77,8 +71,6 @@ describe('Profile Information Component', () => {
'Institution',
'Country of Residence',
'Country of Citizenship',
'Ethnicity',
'Gender',
];
headings.forEach((heading) => {
expect(getByText(heading)).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './HighlightSearchTerm.module.scss';

const HighlightSearchTerm = ({ searchTerm, content }) => {
if (!searchTerm) {
return <>{content}</>;
}

const searchTermRegex = new RegExp(`(${searchTerm})`, 'gi');

const highlightParts = () => {
const parts = content.split(searchTermRegex);
return parts.map((part, i) => {
const isSearchTerm = part.match(searchTermRegex);
return isSearchTerm ? (
<b className={styles['highlight']} key={i}>
{part}
</b>
) : (
part
);
});
};

return <>{highlightParts()}</>;
};

HighlightSearchTerm.propTypes = {
searchTerm: PropTypes.string,
content: PropTypes.string,
};

HighlightSearchTerm.defaultProps = {
searchTerm: '',
content: '',
};

export default HighlightSearchTerm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.highlight {
font-weight: bold;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import { render } from '@testing-library/react';
import {
toBeInTheDocument,
toHaveClass,
toBeNull,
} from '@testing-library/jest-dom';

import HighlightSearchTerm from './HighlightSearchTerm';

describe('HighlightSearchTerm Component', () => {
it('renders content when searchTerm is not provided', () => {
const { getByText } = render(<HighlightSearchTerm content="Lorem ipsum" />);
expect(getByText('Lorem ipsum')).toBeInTheDocument();
});

it('renders without highlighting when searchTerm in content do not match', () => {
const { getByText } = render(
<HighlightSearchTerm
searchTerm="minim"
content="Lorem ipsum dolor sit amet"
/>
);
expect(getByText('Lorem ipsum dolor sit amet')).toBeInTheDocument();
expect(document.querySelector('.highlight')).toBeNull();
});

it('renders content when searchTerm is not provided', () => {
const { getByText } = render(<HighlightSearchTerm content="Lorem ipsum" />);
expect(getByText('Lorem ipsum')).toBeInTheDocument();
});

it('renders content with searchTerm highlighted', () => {
const { getByText } = render(
<HighlightSearchTerm
searchTerm="ipsum"
content="Lorem ipsum dolor sit amet"
/>
);
const highlightedText = getByText('ipsum');
expect(highlightedText).toHaveClass('highlight');
});

it('renders content with multiple searchTerm occurrences highlighted', () => {
const { getAllByText } = render(
<HighlightSearchTerm
searchTerm="ipsum"
content="Lorem ipsum ipsum Loremipsum ipsumipsum dolor sit amet"
/>
);
const highlightedText = getAllByText('ipsum');
expect(highlightedText.length).toBe(5);
highlightedText.forEach((element) => {
expect(element).toHaveClass('highlight');
});
});
});
3 changes: 3 additions & 0 deletions client/src/components/_common/HighlightSearchTerm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import HighlightSearchTerm from './HighlightSearchTerm';

export default HighlightSearchTerm;
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ InfiniteScrollTable.propTypes = {
noDataText: rowContentPropType,
getRowProps: PropTypes.func,
columnMemoProps: PropTypes.arrayOf(PropTypes.any),
cell: PropTypes.object,
};
InfiniteScrollTable.defaultProps = {
onInfiniteScroll: (offset) => {},
Expand Down
1 change: 1 addition & 0 deletions client/src/components/_common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export { default as Icon } from './Icon';
export { default as Message } from './Message';
export { default as InlineMessage } from './InlineMessage';
export { default as SectionMessage } from './SectionMessage';
export { default as HighlightSearchTerm } from './HighlightSearchTerm';
export { default as Sidebar } from './Sidebar';
export { default as DescriptionList } from './DescriptionList';
export { default as DropdownSelector } from './DropdownSelector';
Expand Down
16 changes: 16 additions & 0 deletions client/src/redux/sagas/fixtures/appdetail.fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ const appDetailFixture = {
inputMode: 'REQUIRED',
notes: { fieldType: 'number' },
},
{
arg: 'OpenSeesSP',
name: 'mainProgram',
description: '',
inputMode: 'FIXED',
notes: { isHidden: true },
},
],
containerArgs: [],
schedulerOptions: [
Expand All @@ -86,6 +93,15 @@ const appDetailFixture = {
sourceUrl: null,
targetPath: 'in.txt',
},
{
name: 'hello world',
description: 'hello world description',
inputMode: 'FIXED',
autoMountLocal: true,
sourceUrl: null,
targetPath: '.',
notes: { isHidden: true },
},
],
fileInputArrays: [],
nodeCount: 1,
Expand Down
4 changes: 2 additions & 2 deletions client/src/redux/sagas/fixtures/jobdetail.fixture.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ const jobDetailFixture = {
memoryMB: 100,
maxMinutes: 10,
fileInputs:
'[{"name": "File to modify", "optional": true, "sourceUrl": "tapis://test.community/system/1/user/test/in.txt", "targetPath": "in.txt", "description": "The full greeting will be appended to the target .txt file", "autoMountLocal": true, "srcSharedAppCtx": false, "destSharedAppCtx": true}]',
'[{"name": "File to modify", "optional": true, "sourceUrl": "tapis://test.community/system/1/user/test/in.txt", "targetPath": "in.txt", "description": "The full greeting will be appended to the target .txt file", "autoMountLocal": true, "srcSharedAppCtx": false, "destSharedAppCtx": true}, {"name": "hello world", "optional": false, "sourceUrl": "", "targetPath": ".", "description": "hello world description", "autoMountLocal": true, "srcSharedAppCtx": false, "destSharedAppCtx": true, "notes": "{\\"isHidden\\":\\"true\\"}"}]',
parameterSet:
'{"appArgs": [{"arg": "hello", "name": "Greeting", "notes": "{\\"enum_values\\":[{\\"hello\\":\\"Hello\\"},{\\"hola\\":\\"Hola\\"},{\\"wassup\\":\\"Wassup\\"}]}", "include": null, "description": "Choose a greeting to give to your target"}, {"arg": "world", "name": "Target", "notes": "{}", "include": null, "description": "Whom to address your greeting"}, {"arg": "1", "name": "Sleep Time", "notes": "{\\"fieldType\\":\\"number\\"}", "include": null, "description": "How long to sleep before app execution"}], "envVariables": [{"key": "_tapisAppId", "value": "hello-world", "description": null}, {"key": "_tapisAppVersion", "value": "0.0.1", "description": null}, {"key": "_tapisArchiveOnAppError", "value": "true", "description": null}, {"key": "_tapisArchiveSystemDir", "value": "/home/user/tapis-jobs-archive/2023-01-24Z/hello-world_2023-01-24T23:52:57-e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisArchiveSystemId", "value": "cloud.data", "description": null}, {"key": "_tapisCoresPerNode", "value": "1", "description": null}, {"key": "_tapisDynamicExecSystem", "value": "false", "description": null}, {"key": "_tapisEffectiveUserId", "value": "user", "description": null}, {"key": "_tapisExecSystemExecDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisExecSystemHPCQueue", "value": "development", "description": null}, {"key": "_tapisExecSystemId", "value": "frontera", "description": null}, {"key": "_tapisExecSystemInputDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisExecSystemLogicalQueue", "value": "development", "description": null}, {"key": "_tapisExecSystemOutputDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007/output", "description": null}, {"key": "_tapisJobCreateDate", "value": "2023-01-24Z", "description": null}, {"key": "_tapisJobCreateTime", "value": "23:53:10.922143633Z", "description": null}, {"key": "_tapisJobCreateTimestamp", "value": "2023-01-24T23:53:10.922143633Z", "description": null}, {"key": "_tapisJobName", "value": "hello-world_2023-01-24T23:52:57", "description": null}, {"key": "_tapisJobOwner", "value": "user", "description": null}, {"key": "_tapisJobUUID", "value": "e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisJobWorkingDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisMaxMinutes", "value": "10", "description": null}, {"key": "_tapisMemoryMB", "value": "100", "description": null}, {"key": "_tapisNodes", "value": "1", "description": null}, {"key": "_tapisSysBatchScheduler", "value": "SLURM", "description": null}, {"key": "_tapisSysHost", "value": "frontera.tacc.utexas.edu", "description": null}, {"key": "_tapisSysRootDir", "value": "/", "description": null}, {"key": "_tapisTenant", "value": "portals", "description": null}, {"key": "_webhook_base_url", "value": "https://dev.a2cps.tacc.utexas.edu/webhooks/", "description": null}], "archiveFilter": {"excludes": [], "includes": [], "includeLaunchFiles": true}, "containerArgs": [], "schedulerOptions": [{"arg": "--tapis-profile tacc", "name": "tacc Scheduler Profile", "notes": "{}", "include": null, "description": "Scheduler profile for HPC clusters at TACC"}, {"arg": "-A TACC-ACI", "name": "TACC Allocation", "notes": null, "include": true, "description": "The allocation associated with this job execution"}]}',
'{"appArgs": [{"arg": "hello", "name": "Greeting", "notes": "{\\"enum_values\\":[{\\"hello\\":\\"Hello\\"},{\\"hola\\":\\"Hola\\"},{\\"wassup\\":\\"Wassup\\"}]}", "include": null, "description": "Choose a greeting to give to your target"}, {"arg": "world", "name": "Target", "notes": "{}", "include": null, "description": "Whom to address your greeting"}, {"arg": "1", "name": "Sleep Time", "notes": "{\\"fieldType\\":\\"number\\"}", "include": null, "description": "How long to sleep before app execution"}, {"arg": "OpenSeesSP", "name": "mainProgram", "notes": "{\\"isHidden\\":\\"true\\"}", "include": null, "description": "null"}, {"arg": "OpenSeesSP", "name": "_mainProgram", "include": null, "description": "null"}], "envVariables": [{"key": "_tapisAppId", "value": "hello-world", "description": null}, {"key": "_tapisAppVersion", "value": "0.0.1", "description": null}, {"key": "_tapisArchiveOnAppError", "value": "true", "description": null}, {"key": "_tapisArchiveSystemDir", "value": "/home/user/tapis-jobs-archive/2023-01-24Z/hello-world_2023-01-24T23:52:57-e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisArchiveSystemId", "value": "cloud.data", "description": null}, {"key": "_tapisCoresPerNode", "value": "1", "description": null}, {"key": "_tapisDynamicExecSystem", "value": "false", "description": null}, {"key": "_tapisEffectiveUserId", "value": "user", "description": null}, {"key": "_tapisExecSystemExecDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisExecSystemHPCQueue", "value": "development", "description": null}, {"key": "_tapisExecSystemId", "value": "frontera", "description": null}, {"key": "_tapisExecSystemInputDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisExecSystemLogicalQueue", "value": "development", "description": null}, {"key": "_tapisExecSystemOutputDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007/output", "description": null}, {"key": "_tapisJobCreateDate", "value": "2023-01-24Z", "description": null}, {"key": "_tapisJobCreateTime", "value": "23:53:10.922143633Z", "description": null}, {"key": "_tapisJobCreateTimestamp", "value": "2023-01-24T23:53:10.922143633Z", "description": null}, {"key": "_tapisJobName", "value": "hello-world_2023-01-24T23:52:57", "description": null}, {"key": "_tapisJobOwner", "value": "user", "description": null}, {"key": "_tapisJobUUID", "value": "e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisJobWorkingDir", "value": "/scratch1/12345/user/tapis/e929ad16-adc5-4bd4-b84f-d41d1b67e5ee-007", "description": null}, {"key": "_tapisMaxMinutes", "value": "10", "description": null}, {"key": "_tapisMemoryMB", "value": "100", "description": null}, {"key": "_tapisNodes", "value": "1", "description": null}, {"key": "_tapisSysBatchScheduler", "value": "SLURM", "description": null}, {"key": "_tapisSysHost", "value": "frontera.tacc.utexas.edu", "description": null}, {"key": "_tapisSysRootDir", "value": "/", "description": null}, {"key": "_tapisTenant", "value": "portals", "description": null}, {"key": "_webhook_base_url", "value": "https://dev.a2cps.tacc.utexas.edu/webhooks/", "description": null}], "archiveFilter": {"excludes": [], "includes": [], "includeLaunchFiles": true}, "containerArgs": [], "schedulerOptions": [{"arg": "--tapis-profile tacc", "name": "tacc Scheduler Profile", "notes": "{}", "include": null, "description": "Scheduler profile for HPC clusters at TACC"}, {"arg": "-A TACC-ACI", "name": "TACC Allocation", "notes": null, "include": true, "description": "The allocation associated with this job execution"}]}',
execSystemConstraints: null,
subscriptions: '[]',
blockedCount: 0,
Expand Down
Loading

0 comments on commit 9cbec5c

Please sign in to comment.