Skip to content

Commit

Permalink
Merge branch 'main' into bug/wp-104-view-team-tab
Browse files Browse the repository at this point in the history
  • Loading branch information
chandra-tacc authored Nov 14, 2023
2 parents 9a89284 + 5e6be96 commit ada19e6
Show file tree
Hide file tree
Showing 68 changed files with 1,662 additions and 491 deletions.
37 changes: 36 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [3.3.2] - 2023-11-09: workspace search fails on frontera portal
- WP-380: Remove id prefix filter on workspace search (#898)

## [3.3.1] - 2023-11-07: Search related bug fixes and App Icon fix
- WP-355: Fixing issue with icons on dev/prod sites (#892)
- WP-354: Workspace search - filter results visible to user (#893)
- WP-356: Site Search: For files, use home dir to isolate the search (#897)
- WP-361: Jobs Search - restrict search to a specific portal (#896)

## [3.3.0] - 2023-10-27: V3 integration improvements; bug fixes

### Added

- WP-164 Implement Workspace Search (#886)
- WP-288: Implement Queue Filter for V3 apps (#883)
- WP-100: Display all Job Attributes in Jobs History > View Details (#868)
- WP-72: Workspace Search - Highlight matching search terms (#873)
- WP-273: App Category icon (#874)
- WP-32: Ability to see incomplete onboarding status in onboarding page. (#891)

### Changed

- WP-299: Add Data Files button dropdown needs minor adjustment in alignment (#878)
- WP-65: Data Files: Display full paths for concatenated breadcrumbs or filepaths (#866)
- WP-278: Data Files: Update Design of View Path Modal (#866)
- WP-279: Data Files: Support <TextCopyField> That Can Show All Text (#866)

### Fixed
- WA-314: Input file fixes for hidden and FIXED types (#880)
- WP-66: Refactor DataFiles components to have more descriptive prop and variable names (#885 and #876)
- WP-109-remove-unused-django-fields (#887)
- Fix email confirmation for tickets (#879)

## [3.2.1] - 2023-10-05: Search and Target Path fixes

Expand Down Expand Up @@ -959,7 +991,10 @@ WP-306: Fix target path regression (#871)
## [1.0.0] - 2020-02-28
v1.0.0 Production release as of Feb 28, 2020.

[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.2.1...HEAD
[unreleased]: https://github.com/TACC/Core-Portal/compare/v3.3.2...HEAD
[3.3.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.3.2
[3.3.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.3.1
[3.3.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.3.0
[3.2.1]: https://github.com/TACC/Core-Portal/releases/tag/v3.2.1
[3.2.0]: https://github.com/TACC/Core-Portal/releases/tag/v3.2.0
[3.1.2]: https://github.com/TACC/Core-Portal/releases/tag/v3.1.2
Expand Down
309 changes: 163 additions & 146 deletions client/package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"stylelint": "^14.4.0",
"stylelint-config-recommended": "^7.0.0",
"stylelint-config-standard": "^25.0.0",
"timekeeper": "^2.3.1",
"typescript": "^4.4.3",
"vite": "^2.9.16",
"weak-key": "^1.0.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const AppBrowser = () => {
}
>
<span className="nav-content">
<AppIcon appId={app.appId} />
<AppIcon appId={app.appId} category={category} />
<span className="nav-text">{app.label || app.appId}</span>
</span>
</NavLink>
Expand Down
35 changes: 29 additions & 6 deletions client/src/components/Applications/AppForm/AppForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ const AdjustValuesWhenQueueChanges = ({ app }) => {
};

const AppInfo = ({ app }) => {
const categoryDict = useSelector((state) => state.apps.categoryDict);
const getAppCategory = (appId) => {
for (const [cat, apps] of Object.entries(categoryDict)) {
if (apps.some((app) => app.appId === appId)) {
return cat;
}
}
return null;
};

const appCategory = getAppCategory(app.definition.id);

return (
<div className="appInfo-wrapper">
<h5 className="appInfo-title">{app.definition.label}</h5>
Expand All @@ -163,7 +175,7 @@ const AppInfo = ({ app }) => {
target="_blank"
rel="noreferrer noopener"
>
<AppIcon appId={app.definition.id} />{' '}
<AppIcon appId={app.definition.id} category={appCategory} />{' '}
<span>{app.definition.notes.label} Documentation</span>
</a>
) : null}
Expand Down Expand Up @@ -484,6 +496,7 @@ export const AppSchemaForm = ({ app }) => {
targetDir: isTargetPathField(k) ? v : null,
};
})
.filter((v) => v) //filter nulls
.reduce((acc, entry) => {
// merge input field and targetPath fields into one.
const key = getInputFieldFromTargetPathField(entry.name);
Expand Down Expand Up @@ -691,11 +704,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
226 changes: 224 additions & 2 deletions client/src/components/Applications/AppForm/AppForm.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { render, waitFor } from '@testing-library/react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { BrowserRouter } from 'react-router-dom';
Expand All @@ -15,11 +16,16 @@ import {
appTrayExpectedFixture,
} from '../../../redux/sagas/fixtures/apptray.fixture';
import { initialAppState } from '../../../redux/reducers/apps.reducers';
import { helloWorldAppFixture } from './fixtures/AppForm.app.fixture';
import {
helloWorldAppFixture,
helloWorldAppSubmissionPayloadFixture,
} from './fixtures/AppForm.app.fixture';
import systemsFixture from '../../DataFiles/fixtures/DataFiles.systems.fixture';
import { projectsFixture } from '../../../redux/sagas/fixtures/projects.fixture';
import '@testing-library/jest-dom/extend-expect';
import timekeeper from 'timekeeper';

const frozenDate = '2023-10-01';
const mockStore = configureStore();
const initialMockState = {
allocations: allocationsFixture,
Expand Down Expand Up @@ -56,6 +62,11 @@ function renderAppSchemaFormComponent(store, app) {
}

describe('AppSchemaForm', () => {
beforeAll(() => {
// Lock Time
timekeeper.freeze(new Date(frozenDate));
});

it('renders the AppSchemaForm', async () => {
const store = mockStore({
...initialMockState,
Expand Down Expand Up @@ -257,6 +268,162 @@ describe('AppSchemaForm', () => {
expect(getByText(/Activate your Application Name license/)).toBeDefined();
});
});

it('job submission with file input mode FIXED', async () => {
const store = mockStore({
...initialMockState,
});

const { getByText, container } = renderAppSchemaFormComponent(store, {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
jobAttributes: {
...helloWorldAppFixture.definition.jobAttributes,
fileInputs: [
{
name: 'File to copy',
description: 'A fixed file used by the app',
inputMode: 'FIXED',
autoMountLocal: true,
sourceUrl:
'tapis://corral-tacc/tacc/aci/secure-test/rallyGolf.jpg',
targetPath: 'rallyGolf.jpg',
},
],
},
},
});
const hiddenFileInput = container.querySelector(
'input[name="fileInputs.File to copy"]'
);
// FIXED fields are still shown in UI but not submitted.
expect(hiddenFileInput).toBeInTheDocument();

const submitButton = getByText(/Submit/);
fireEvent.click(submitButton);
const payload = {
...helloWorldAppSubmissionPayloadFixture,
job: {
...helloWorldAppSubmissionPayloadFixture.job,
name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00',
},
};

await waitFor(() => {
expect(store.getActions()).toEqual([
{ type: 'GET_SYSTEM_MONITOR' },
{ type: 'SUBMIT_JOB', payload: payload },
]);
});
});

it('job submission with file input hidden', async () => {
const store = mockStore({
...initialMockState,
});

const { getByText, container } = renderAppSchemaFormComponent(store, {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
jobAttributes: {
...helloWorldAppFixture.definition.jobAttributes,
fileInputs: [
{
name: 'File to copy',
description: 'A fixed file used by the app',
inputMode: 'REQUIRED',
autoMountLocal: true,
sourceUrl:
'tapis://corral-tacc/tacc/aci/secure-test/rallyGolf.jpg',
targetPath: 'rallyGolf.jpg',
notes: {
isHidden: true,
},
},
],
},
},
});

const hiddenFileInput = container.querySelector(
'input[name="fileInputs.File to copy"]'
);
expect(hiddenFileInput).not.toBeInTheDocument();

const submitButton = getByText(/Submit/);
fireEvent.click(submitButton);
const payload = {
...helloWorldAppSubmissionPayloadFixture,
job: {
...helloWorldAppSubmissionPayloadFixture.job,
name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00',
},
};

await waitFor(() => {
expect(store.getActions()).toEqual([
{ type: 'GET_SYSTEM_MONITOR' },
{ type: 'SUBMIT_JOB', payload: payload },
]);
});
});

it('job submission with custom target path', async () => {
const store = mockStore({
...initialMockState,
});
const { getByText, container } = renderAppSchemaFormComponent(store, {
...helloWorldAppFixture,
definition: {
...helloWorldAppFixture.definition,
notes: {
...helloWorldAppFixture.definition.notes,
showTargetPath: true,
},
},
});

const fileInput = container.querySelector(
'input[name="fileInputs.File to modify"]'
);
const file = 'tapis://foo/bar.txt';
const targetPathForFile = 'baz.txt';
fireEvent.change(fileInput, { target: { value: file } });
const targetPathInput = container.querySelector(
'input[name="fileInputs._TargetPath_File to modify"]'
);
fireEvent.change(targetPathInput, { target: { value: targetPathForFile } });

const submitButton = getByText(/Submit/);
fireEvent.click(submitButton);
const payload = {
...helloWorldAppSubmissionPayloadFixture,
job: {
...helloWorldAppSubmissionPayloadFixture.job,
fileInputs: [
{
name: 'File to modify',
sourceUrl: file,
targetPath: targetPathForFile,
},
],
name: 'hello-world-0.0.1_' + frozenDate + 'T00:00:00',
},
};

await waitFor(() => {
expect(store.getActions()).toEqual([
{ type: 'GET_SYSTEM_MONITOR' },
{ type: 'SUBMIT_JOB', payload: payload },
]);
});
});

afterAll(() => {
timekeeper.reset();
});
});

describe('AppDetail', () => {
Expand All @@ -275,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');
});
});
Loading

0 comments on commit ada19e6

Please sign in to comment.