Skip to content

Commit

Permalink
Merge pull request #2223 from nulib/deploy/staging
Browse files Browse the repository at this point in the history
Deploy Meadow v1.7.1 to production
  • Loading branch information
kdid authored May 18, 2021
2 parents 0b5d070 + faeb456 commit 5da6bc9
Show file tree
Hide file tree
Showing 60 changed files with 1,741 additions and 1,146 deletions.
15 changes: 14 additions & 1 deletion .circleci/scripts/update_ecs_service.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
#!/bin/bash

changed_files=$(git diff --name-only HEAD HEAD^)
case $changed_files in
lib/meadow/indexing/*)
reindex=true
;;
priv/elasticsearch/*)
reindex=true
;;
*)
reindex=false
;;
esac

networkconfig=$(aws ecs describe-services --cluster ${ECS_CLUSTER} --service ${ECS_SERVICE} | jq -cM '.services[0].networkConfiguration')
overrides='{"containerOverrides":[{"name":"'${ECS_CONTAINER}'","environment": [{"name": "MEADOW_PROCESSES", "value": "none"}, {"name": "DB_POOL_SIZE", "value": "10"}],"command":["eval","Meadow.ReleaseTasks.migrate()"]}]}'
overrides='{"containerOverrides":[{"name":"'${ECS_CONTAINER}'","environment": [{"name": "MEADOW_PROCESSES", "value": "none"}, {"name": "DB_POOL_SIZE", "value": "10"}],"command":["eval","Meadow.ReleaseTasks.migrate('${reindex}')"]}]}'
aws ecs run-task --platform-version 1.4.0 --cluster ${ECS_CLUSTER} --task-definition ${ECS_TASK} --overrides "${overrides}" --launch-type FARGATE --network-configuration ${networkconfig}
for service in $(aws ecs list-services --cluster meadow | jq -r '.serviceArns[] | split("/") | last'); do
aws ecs update-service --cluster ${ECS_CLUSTER} --service ${service} --force-new-deployment
Expand Down
3 changes: 3 additions & 0 deletions assets/js/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const client = new ApolloClient({
link: link,
cache: new InMemoryCache({
typePolicies: {
ControlledValue: {
keyFields: ["id", "hint"]
},
FileSet: {
fields: {
metadata: { merge: false },
Expand Down
18 changes: 13 additions & 5 deletions assets/js/components/BatchEdit/Administrative/ProjectMetadata.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import React from "react";
import PropTypes from "prop-types";
import UIFormBatchFieldArray from "../../UI/Form/BatchFieldArray";
import { PROJECT_METADATA } from "../../../services/metadata";
import { PROJECT_METADATA } from "@js/services/metadata";
import UIFormField from "@js/components/UI/Form/Field";
import UIFormInput from "@js/components/UI/Form/Input";

const BatchEditAdministrativeProjectMetadata = ({ ...restProps }) => {
return (
<div data-testid="project-metadata" {...restProps}>
{PROJECT_METADATA.map((item) => (
<div key={item.name} data-testid={item.name}>
<UIFormBatchFieldArray required name={item.name} label={item.label} />
</div>
// <div key={item.name} data-testid={item.name}>
// <UIFormBatchFieldArray required name={item.name} label={item.label} />
// </div>
<UIFormField key={item.name} label={item.label}>
<UIFormInput
data-testid={item.name}
isReactHookForm
placeholder={item.label}
name={item.name}
label={item.label}
/>
</UIFormField>
))}

<UIFormField label="Project Cycle" data-testid="projectCycle">
Expand Down
7 changes: 6 additions & 1 deletion assets/js/components/BatchEdit/Tabs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
prepControlledTermInput,
prepFacetKey,
prepRelatedUrl,
PROJECT_METADATA,
} from "@js/services/metadata";
import UITabsStickyHeader from "@js/components/UI/Tabs/StickyHeader";
import { Button } from "@nulib/admin-react-components";
Expand Down Expand Up @@ -64,7 +65,6 @@ export default function BatchEditTabs() {
* @param {Object} data Comes from React Hook Form
*/
const onSubmit = (data) => {
console.log("data", data);
// "data" here returns everything (which was set above in the useEffect()),
// including fields that are either outdated or which no values were ever registered
// with React Hook Form's register(). So, we'll use getValues() to get the real data
Expand Down Expand Up @@ -102,6 +102,11 @@ export default function BatchEditTabs() {
if (currentFormValues.projectCycle) {
replaceItems.administrative.projectCycle = currentFormValues.projectCycle;
}
PROJECT_METADATA.forEach((pm) => {
if (currentFormValues[pm.name]) {
replaceItems.administrative[pm.name] = [currentFormValues[pm.name]];
}
});

// Update controlled term values to match shape the GraphQL mutation expects
for (let term of CONTROLLED_METADATA) {
Expand Down
58 changes: 58 additions & 0 deletions assets/js/components/UI/Dropdown.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import PropTypes from "prop-types";
import { IconArrowDown } from "@js/components/Icon";
import classNames from "classnames";

function UIDropdown({
id = "ui-dropdown",
isRight,
label = "Actions",
children,
...restProps
}) {
const [isActive, setIsActive] = React.useState();

return (
<div
className={classNames(["dropdown"], {
"is-active": isActive,
"is-right": isRight,
})}
{...restProps}
>
<div className="dropdown-trigger" data-testid="dropdown-trigger">
<button
onClick={() => setIsActive(!isActive)}
className="button"
aria-haspopup="true"
aria-controls={id}
data-testid="dropdown-trigger-button"
>
<span>{label}</span>
<span className="icon is-small">
<IconArrowDown aria-hidden="true" />
</span>
</button>
</div>
<div
className="dropdown-menu"
id={id}
data-testid="dropdown-menu"
role="menu"
>
<div className="dropdown-content" data-testid="dropdown-content">
{children}
</div>
</div>
</div>
);
}

UIDropdown.propTypes = {
id: PropTypes.string,
isRight: PropTypes.bool,
label: PropTypes.string,
children: PropTypes.node,
};

export default UIDropdown;
36 changes: 36 additions & 0 deletions assets/js/components/UI/Dropdown.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";
import UIDropdown from "./Dropdown";

describe("UIDropdown component", () => {
beforeEach(() => {
render(
<UIDropdown data-testid="test-dropdown" id="dropdown1">
<a href="#">Option 1</a>
<a href="#">Option 2</a>
</UIDropdown>
);
});

it("renders the component ", async () => {
expect(screen.getByTestId("test-dropdown"));
expect(screen.getByTestId("dropdown-trigger"));
});

it("renders the id attribute for accessibility", () => {
const el = screen.getByTestId("dropdown-menu");
expect(el.id).toEqual("dropdown1");
});

it("renders dropdown content", () => {
const dropdownEl = screen.getByTestId("test-dropdown");
const el = screen.getByTestId("dropdown-content");

expect(el.childElementCount).toEqual(2);
expect(dropdownEl).not.toHaveClass("is-active");

userEvent.click(screen.getByTestId("dropdown-trigger-button"));
expect(dropdownEl).toHaveClass("is-active");
});
});
28 changes: 28 additions & 0 deletions assets/js/components/UI/DropdownItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react";
import PropTypes from "prop-types";
import classNames from "classnames";

function UIDropdownItem({ as = "a", isActive, children, ...restProps }) {
const Tag = as;
const aProps = {
href: "#",
};
return (
<Tag
{...(as === "a" && { ...aProps })}
className={classNames(["dropdown-item"], {
"is-active": isActive,
})}
{...restProps}
>
{children}
</Tag>
);
}

UIDropdownItem.propTypes = {
isActive: PropTypes.bool,
children: PropTypes.node,
};

export default UIDropdownItem;
47 changes: 47 additions & 0 deletions assets/js/components/UI/DropdownItem.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { screen, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";
import UIDropdownItem from "./DropdownItem";

const mockHandleClick = jest.fn();

describe("UIDropdownItem component", () => {
describe("default implementation", () => {
beforeEach(() => {
render(
<UIDropdownItem
data-testid="test-dropdown-item"
onClick={mockHandleClick}
>
Option 1
</UIDropdownItem>
);
});

it("renders the component", async () => {
expect(screen.getByTestId("test-dropdown-item"));
expect(screen.getByText("Option 1"));
});

it("handles click event", () => {
userEvent.click(screen.getByTestId("test-dropdown-item"));
expect(mockHandleClick).toHaveBeenCalled();
});
});

describe("custom implementation", () => {
it("renders as dynamic HTML element", async () => {
render(
<UIDropdownItem
as="div"
data-testid="test-dropdown-item"
onClick={mockHandleClick}
>
Option 1
</UIDropdownItem>
);
const el = screen.getByTestId("test-dropdown-item");
expect(el.tagName).toEqual("DIV");
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const WorkTabsAdministrative = ({ work }) => {
updatedAt,
} = work;
const [isEditing, setIsEditing] = useIsEditing();
const methods = useForm();
const { handleFacetLinkClick } = useFacetLinkClick();

const [
updateWork,
Expand All @@ -49,26 +51,15 @@ const WorkTabsAdministrative = ({ work }) => {
awaitRefetchQueries: true,
});
const {
libraryUnit,
preservationLevel,
status,
projectCycle,
} = administrativeMetadata;

const methods = useForm();
const history = useHistory();
const { handleFacetLinkClick } = useFacetLinkClick();

useEffect(() => {
// Update a Work after the form has been submitted
let resetValues = {};
for (let group of [PROJECT_METADATA]) {
for (let obj of group) {
resetValues[obj.name] = administrativeMetadata[obj.name].map(
(value) => ({
metadataItem: value,
})
);
resetValues[obj.name] = administrativeMetadata[obj.name][0];
}
}
methods.reset({
Expand All @@ -79,6 +70,7 @@ const WorkTabsAdministrative = ({ work }) => {

const onSubmit = (data) => {
let currentFormValues = methods.getValues();
console.log(`currentFormValues`, currentFormValues)

let workUpdateInput = {
administrativeMetadata: {
Expand Down Expand Up @@ -106,7 +98,7 @@ const WorkTabsAdministrative = ({ work }) => {
for (let term of PROJECT_METADATA) {
workUpdateInput.administrativeMetadata[
term.name
] = prepFieldArrayItemsForPost(currentFormValues[term.name]);
] = [currentFormValues[term.name]];
}

updateWork({
Expand Down Expand Up @@ -240,20 +232,20 @@ const WorkTabsAdministrative = ({ work }) => {

{PROJECT_METADATA.map((item) => {
return (
<div key={item.name} data-testid={item.name}>
<UIFormField label={item.label} key={item.name} data-testid={item.name}>
{isEditing ? (
<UIFormFieldArray
required
name={item.name}
<UIFormInput
isReactHookForm
// NOTE: Eventually Project data will come in as single values instead of an array
defaultValue={administrativeMetadata[item.name][0]}
label={item.label}
name={item.name}
placeholder={item.label}
/>
) : (
<UIFormFieldArrayDisplay
values={administrativeMetadata[item.name]}
label={item.label}
/>
<p>{administrativeMetadata[item.name][0]}</p>
)}
</div>
</UIFormField>
);
})}
<div className="field content">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from "react";
import { renderWithRouterApollo } from "../../../services/testing-helpers";
import { mockWork } from "../work.gql.mock";
import { renderWithRouterApollo } from "../../../../services/testing-helpers";
import { mockWork } from "../../work.gql.mock";
import WorkTabsAdministrative from "./Administrative";
import { fireEvent, waitFor, screen } from "@testing-library/react";
import {
getCollectionMock,
getCollectionsMock,
} from "@js/components/Collection/collection.gql.mock";
import { mockUser } from "../../Auth/auth.gql.mock";
import { mockUser } from "../../../Auth/auth.gql.mock";
import userEvent from "@testing-library/user-event";
import { allCodeListMocks } from "@js/components/Work/controlledVocabulary.gql.mock";
import { CodeListProvider } from "@js/context/code-list-context";
Expand Down
Loading

0 comments on commit 5da6bc9

Please sign in to comment.