Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
05cd2eb
fix(unity-react-core): fixed success font and title
spaceperson Jul 14, 2026
e0e6a2d
refactor(unity-react-core): removed unused import
spaceperson Jul 17, 2026
fc9d817
fix(unity-bootstrap-theme): fixed linting error
spaceperson Jul 20, 2026
73b1772
feat(component-events): expose configurable noFeedText prop
juanmitriatti Jun 16, 2026
15e0d14
chore(component-events): drop manual version bump and changelog entry
juanmitriatti Jul 8, 2026
45ff937
fix(component-events): fall back to default noFeedText when blank
juanmitriatti Jul 8, 2026
533a8cb
chore(release): 3.2.0 [skip ci]
semantic-release-bot Jul 14, 2026
bc5ce60
fix(unity-bootstrap-theme): keep hero CTA inside the hero box below m…
juanmitriatti Jul 10, 2026
cbb437d
chore(release): 1.39.6 [skip ci]
semantic-release-bot Jul 14, 2026
778e233
fix(unity-bootstrap-theme): add bottom spacing to hero-sm title when …
juanmitriatti Jul 12, 2026
41da073
chore(release): 1.39.7 [skip ci]
semantic-release-bot Jul 14, 2026
2fe46d6
docs(unity-react-core): add todos for tabbed panels
davidornelas11 Dec 19, 2025
49c79f4
fix(unity-react-core): toDo 1.1
oatkar Dec 22, 2025
e61aadb
fix(unity-react-core): to do 1.2
oatkar Jan 2, 2026
e28eee5
docs: add review notes
davidornelas11 Jan 6, 2026
1f1a7dc
fix(unity-react-core): changes
oatkar Jan 22, 2026
be0c9dc
feat(unity-react-core): toDo 1.3
oatkar Jan 29, 2026
728e826
fix(unity-react-core): 2.1
oatkar Mar 17, 2026
ee26893
fix(unity-react-core): 2.1 changes
oatkar Mar 17, 2026
1b1e617
fix(unity-react-core): 2.2 with changes in tabheader.jsx file
oatkar Mar 18, 2026
c627e38
fix(unity-react-core): fix two issues in pr
oatkar Mar 24, 2026
71d462b
feat(unity-react-core): tODO 2.3
oatkar Apr 1, 2026
7df4c64
feat(unity-bootstrap-theme): tODO 3.1
oatkar Apr 1, 2026
9499bf7
fix(unity-bootstrap-theme): todo 3.2
oatkar Apr 1, 2026
7f0db66
fix(unity-bootstrap-theme): todo 3.3, changed MoreDropdown.js to fit …
oatkar Apr 1, 2026
a024e13
feat(unity-bootstrap-theme): todo 3.2
oatkar Apr 3, 2026
ade474a
feat(unity-react-core): phase 4
oatkar Apr 7, 2026
825c9fe
fix(unity-react-core): toDo 5.1
oatkar Apr 10, 2026
12c1b80
fix(unity-react-core): toDo 5.2
oatkar Apr 10, 2026
b7301c3
fix(unity-react-core): final design before completing all tests
oatkar Apr 13, 2026
f2e8486
fix(unity-react-core): final design before completeing tests
oatkar Apr 13, 2026
faadc24
fix(unity-react-core): added scrolling feature
oatkar Apr 13, 2026
dfe1938
fix(unity-react-core): scrolling feature final
oatkar Apr 13, 2026
efc1405
fix(unity-react-core): changes made after review
oatkar Apr 23, 2026
165fc71
feat(unity-react-core): tabbed Panel Rewrite
davidornelas11 May 13, 2026
0d4f8da
feat(unity-react-core): rewrite tabbed panels
davidornelas11 May 13, 2026
f4f3bc4
feat(unity-bootstrap-theme): tabbed panel rewrite
davidornelas11 May 13, 2026
24272ee
chore(unity-react-core): add ts ignore for story file
davidornelas11 May 14, 2026
9cd00b0
fix(unity-react-core): add NavControls for app-webdir-ui use
davidornelas11 May 14, 2026
b2bc75b
chore(unity-react-core): add stories to tsconfig ignore since dev only
davidornelas11 May 14, 2026
808b260
fix(unity-react-core): readd stories to Typescript config
davidornelas11 May 14, 2026
e850096
chore(unity-react-core): update imported packages
davidornelas11 May 14, 2026
5549cdd
chore(unity-react-core): update yarn lock
davidornelas11 May 14, 2026
486b855
docs(unity-react-core): add story controls to tabbed panel story
davidornelas11 May 14, 2026
da3ea1e
fix(unity-bootstrap-theme): update tabbed panel JS
davidornelas11 May 14, 2026
7e9bff9
fix(unity-bootstrap-theme): update tabbed panel JS and styles
davidornelas11 May 14, 2026
cfe76fa
fix(unity-react-core): remove focus on more tabbed panel click
davidornelas11 May 14, 2026
3893112
style(unity-bootstrap-theme): linting
davidornelas11 May 14, 2026
1b56b26
fix(unity-bootstrap-theme): fix safari dropdown issue in tab panels
davidornelas11 May 15, 2026
78496cf
fix(unity-bootstrap-theme): update tabbed panel JS
davidornelas11 May 15, 2026
8a1366b
fix(unity-react-core): update tabbed panels markup
davidornelas11 May 15, 2026
e3e3eac
chore(unity-react-core): linting
davidornelas11 May 15, 2026
de152b0
fix(unity-react-core): update dropdown for tabbed panel placement
davidornelas11 Jun 4, 2026
d9020c5
fix(unity-bootstrap-theme): update tabbed panel JS to mimic react ver…
davidornelas11 Jun 4, 2026
16e2c7a
fix(unity-bootstrap-theme): update tabbed panel JS
davidornelas11 Jun 4, 2026
d912b43
fix(unity-react-core): update tabbed panel logic
davidornelas11 Jun 4, 2026
c95c889
fix(app-degree-pages): degree links point to degree search degree pages
oatkar Jun 30, 2026
7f99401
Revert "fix(app-degree-pages): degree links point to degree search de…
davidornelas11 Jun 30, 2026
bd5a11d
fix(unity-react-core): address tabbed panel pr comments
davidornelas11 Jul 1, 2026
61784ec
fix(unity-react-core): fix resize issue with react tabbed panel
davidornelas11 Jul 8, 2026
32201c3
fix(unity-react-core): fix react more dropdown disappearing
davidornelas11 Jul 17, 2026
a83b7dc
fix(unity-bootstrap-theme): update bootstrap tabbed panels JS and styles
davidornelas11 Jul 17, 2026
abead08
chore(release): 2.0.0 [skip ci]
semantic-release-bot Jul 17, 2026
dd8d01b
chore(release): 2.0.0 [skip ci]
semantic-release-bot Jul 17, 2026
b51e5aa
fix(shared): fixed yarn lock
spaceperson Jul 20, 2026
732af01
fix(unity-react-core): 2.2 with changes in tabheader.jsx file
oatkar Mar 18, 2026
b2f8f36
feat(unity-react-core): tabbed Panel Rewrite
davidornelas11 May 13, 2026
244338c
feat(unity-react-core): rewrite tabbed panels
davidornelas11 May 13, 2026
cf4b73e
fix(unity-react-core): add NavControls for app-webdir-ui use
davidornelas11 May 14, 2026
86adba3
fix(app-degree-pages): degree links point to degree search degree pages
oatkar Jun 30, 2026
9573405
fix(unity-react-core): 2.2 with changes in tabheader.jsx file
oatkar Mar 18, 2026
a2a6df4
feat(unity-react-core): tabbed Panel Rewrite
davidornelas11 May 13, 2026
c860877
feat(unity-react-core): rewrite tabbed panels
davidornelas11 May 13, 2026
11d6eda
fix(unity-react-core): add NavControls for app-webdir-ui use
davidornelas11 May 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,13 @@ const AccordionView = ({ programs, actionUrls }) => {
content: {
header: resolver.getMajorDesc(),
body: `<ul>
<li>
<strong>Major:</strong>
<br />
${majorNameHtml}
</li>
<li>
<strong>Major:</strong>
<br />
<a href=${resolver.getDegreeSearchUrl()}>
${resolver.getMajorDesc()}
</a>
</li>
<li>
<strong>Degree:</strong>
<br />${resolver.getDegree()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ function GridView({ programs, loading, actionUrls }) {
image={imageUrl}
imageAltText="An example image"
title={resolver.getMajorDesc()}
linkLabel={url ? "View Program Details" : undefined}
linkUrl={url || undefined}
linkLabel="View Program Details"
linkUrl={resolver.getDegreeSearchUrl()}
buttons={[
{
color: "maroon",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,19 @@ const columns = [
label: "Major",
className: "major",
sortable: true,
contentTemplate: ({ resolver, rowIndex, actionUrls, onClick }) => {
const url = resolver.getDegreeSearchUrl();
return (
<div className="cell-container">
{url ? (
<a href={url}>{resolver.getMajorDesc()}</a>
) : (
<span>{resolver.getMajorDesc()}</span>
)}
<ChevronIconButton
dataId="show-row-detail"
ariaLabel={`${resolver.getMajorDesc()} arrow`}
ariaControls={`row-info-${rowIndex}`}
onClick={selected => onClick(rowIndex, selected)}
/>
</div>
);
},
contentTemplate: ({ resolver, rowIndex, actionUrls, onClick }) => (
<div className="cell-container">
<a href={resolver.getDegreeSearchUrl()}>
{resolver.getMajorDesc()}
</a>
<ChevronIconButton
dataId="show-row-detail"
ariaLabel={`${resolver.getMajorDesc()} arrow`}
ariaControls={`row-info-${rowIndex}`}
onClick={selected => onClick(rowIndex, selected)}
/>
</div>
),
},
{
dataKey: "Degree",
Expand Down
12 changes: 12 additions & 0 deletions packages/component-events/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# [@asu/component-events-v3.2.0](https://github.com/asu/asu-unity-stack/compare/@asu/component-events-v3.1.0...@asu/component-events-v3.2.0) (2026-07-14)


### Bug Fixes

* **component-events:** fall back to default noFeedText when blank ([e85d4da](https://github.com/asu/asu-unity-stack/commit/e85d4dacd9d7ee6138805fd505ceabca737f3aeb))


### Features

* **component-events:** expose configurable noFeedText prop ([9cac3e9](https://github.com/asu/asu-unity-stack/commit/9cac3e912e1b0bc4c573f8e72378b1d147b0bce8))

# [@asu/component-events-v3.1.0](https://github.com/asu/asu-unity-stack/compare/@asu/component-events-v3.0.1...@asu/component-events-v3.1.0) (2026-04-03)


Expand Down
2 changes: 1 addition & 1 deletion packages/component-events/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@asu/component-events",
"version": "3.1.0",
"version": "3.2.0",
"description": "ASU Events component",
"main": "./dist/asuEvents.cjs.js",
"browser": "./dist/asuEvents.umd.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { GridView } from "./GridView";
* @param {FeedType} props
* @returns {JSX.Element}
*/
const CardsGridEvents = ({ header, ctaButton, dataSource, maxItems }) => {
const CardsGridEvents = ({
header,
ctaButton,
dataSource,
maxItems,
noFeedText = "No events to show.",
}) => {
useEffect(() => {
if (typeof window !== "undefined") {
trackReactComponent({
Expand All @@ -33,7 +39,7 @@ const CardsGridEvents = ({ header, ctaButton, dataSource, maxItems }) => {
}, []);
return (
// Calling the high order component that fetch the data
<BaseFeed {...{ header, ctaButton, dataSource, maxItems }}>
<BaseFeed {...{ header, ctaButton, dataSource, maxItems, noFeedText }}>
<GridView />
</BaseFeed>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,20 @@ WithNoHeader.args = {
url: "/api/mocks/feeds-json",
},
};

/**
* Demonstrates a custom "no results" message. The empty data source forces the
* feed to render the `noFeedText` instead of cards.
* @type {{ args: FeedType, parameters: object}}
*/
export const WithCustomNoFeedText = Template.bind({});
WithCustomNoFeedText.args = {
header: { color: "dark", text: "Events Cards" },
dataSource: {
url: "/api/mocks/empty-feeds-json",
},
noFeedText: "There are no upcoming events at this time.",
};
WithCustomNoFeedText.parameters = {
msw: { handlers: createMockHandlers({ empty: true }) },
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
import { render, cleanup, act } from "@testing-library/react";
import React from "react";
import { vi } from "vitest";

import { CardsGridEvents } from "./index";

Expand Down Expand Up @@ -63,6 +64,49 @@ describe("#Cards Grid Events", () => {
});
});

describe("#No feed text", () => {
// Force an empty feed so the "no results" message is rendered
const emptyFeedArgs = { ...defaultArgs, dataSource: { url: "/empty" } };

beforeEach(() => {
vi.mocked(fetch).mockImplementation(
async () =>
new Response(JSON.stringify({ nodes: [] }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
);
});

afterEach(() => {
vi.mocked(fetch).mockReset();
cleanup();
});

it("should render the default no-feed text when noFeedText is not provided", async () => {
await renderCardsGridEvents(emptyFeedArgs);
expect(
await component.findByText("No events to show.")
).toBeInTheDocument();
});

it("should render a custom no-feed text when noFeedText is provided", async () => {
const customText = "Nothing happening right now.";
await renderCardsGridEvents({ ...emptyFeedArgs, noFeedText: customText });
expect(await component.findByText(customText)).toBeInTheDocument();
expect(
component.queryByText("No events to show.")
).not.toBeInTheDocument();
});

it("should fall back to the default no-feed text when noFeedText is empty", async () => {
await renderCardsGridEvents({ ...emptyFeedArgs, noFeedText: "" });
expect(
await component.findByText("No events to show.")
).toBeInTheDocument();
});
});

describe("#With No Header", () => {
const noHeaderArgs = { ...defaultArgs, header: undefined };
beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import { ListView } from "./ListView";
* @param {FeedType} props
* @returns {JSX.Element}
*/
const CardsListEvents = ({ header, ctaButton, dataSource, maxItems }) => {
const CardsListEvents = ({
header,
ctaButton,
dataSource,
maxItems,
noFeedText = "No events to show.",
}) => {
useEffect(() => {
if (typeof window !== "undefined") {
trackReactComponent({
Expand All @@ -34,7 +40,7 @@ const CardsListEvents = ({ header, ctaButton, dataSource, maxItems }) => {

return (
// Calling the high order component that fetch the data
<BaseFeed {...{ header, ctaButton, dataSource, maxItems }}>
<BaseFeed {...{ header, ctaButton, dataSource, maxItems, noFeedText }}>
<ListView />
</BaseFeed>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,20 @@ WithNoHeader.args = {
url: "/api/mocks/feeds-json",
},
};

/**
* Demonstrates a custom "no results" message. The empty data source forces the
* feed to render the `noFeedText` instead of cards.
* @type {{ args: FeedType, parameters: object}}
*/
export const WithCustomNoFeedText = Template.bind({});
WithCustomNoFeedText.args = {
header: { color: "dark", text: "Events List" },
dataSource: {
url: "/api/mocks/empty-feeds-json",
},
noFeedText: "There are no upcoming events at this time.",
};
WithCustomNoFeedText.parameters = {
msw: { handlers: createMockHandlers({ empty: true }) },
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-check
import { render, cleanup, act } from "@testing-library/react";
import React from "react";
import { vi } from "vitest";

import { CardsListEvents } from "./index";

Expand Down Expand Up @@ -63,6 +64,49 @@ describe("#Cards List Events", () => {
});
});

describe("#No feed text", () => {
// Force an empty feed so the "no results" message is rendered
const emptyFeedArgs = { ...defaultArgs, dataSource: { url: "/empty" } };

beforeEach(() => {
vi.mocked(fetch).mockImplementation(
async () =>
new Response(JSON.stringify({ nodes: [] }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
);
});

afterEach(() => {
vi.mocked(fetch).mockReset();
cleanup();
});

it("should render the default no-feed text when noFeedText is not provided", async () => {
await renderCardsListEvents(emptyFeedArgs);
expect(
await component.findByText("No events to show.")
).toBeInTheDocument();
});

it("should render a custom no-feed text when noFeedText is provided", async () => {
const customText = "Nothing happening right now.";
await renderCardsListEvents({ ...emptyFeedArgs, noFeedText: customText });
expect(await component.findByText(customText)).toBeInTheDocument();
expect(
component.queryByText("No events to show.")
).not.toBeInTheDocument();
});

it("should fall back to the default no-feed text when noFeedText is empty", async () => {
await renderCardsListEvents({ ...emptyFeedArgs, noFeedText: "" });
expect(
await component.findByText("No events to show.")
).toBeInTheDocument();
});
});

describe("#With No Header", () => {
const noHeaderArgs = { ...defaultArgs, header: undefined };
beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ import { defaultProps } from "../../constants/default-props";
import { filterData } from "../../services/dataManager";
import { transformData } from "../../transformers/data.transfromer";

const BaseFeed = ({ children, header, ctaButton, dataSource, maxItems }) => (
const DEFAULT_NO_FEED_TEXT = "No events to show.";

const BaseFeed = ({
children,
header,
ctaButton,
dataSource,
maxItems,
noFeedText = DEFAULT_NO_FEED_TEXT,
}) => (
// Calling the unity-react-core component to fetch the data, transform it and filter it
// We provide in the renderBody the view specified before in the parent component, recieved as "children" in this component.
// We provide in the renderHeader the unity-react-core header, if it is desired to be shown
Expand All @@ -36,7 +45,7 @@ const BaseFeed = ({ children, header, ctaButton, dataSource, maxItems }) => (
dataFilter={filterData}
dataSource={dataSource}
defaultProps={defaultProps}
noFeedText="No events to show."
noFeedText={noFeedText.trim() ? noFeedText : DEFAULT_NO_FEED_TEXT}
maxItems={maxItems}
/>
);
Expand All @@ -46,6 +55,7 @@ BaseFeed.propTypes = {
ctaButton: feedCtaButtonShape,
dataSource: feedDataSourceShape,
maxItems: PropTypes.number,
noFeedText: PropTypes.string,
children: PropTypes.element,
};

Expand Down
1 change: 1 addition & 0 deletions packages/component-events/src/core/models/propTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const eventsPropTypes = {
ctaButton: layoutCTAPropTypes,
dataSource: dataSourcePropTypes,
maxItems: PropTypes.number,
noFeedText: PropTypes.string,
};

export {
Expand Down
19 changes: 17 additions & 2 deletions packages/component-events/src/core/utils/story-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@
import { http, HttpResponse } from "msw";
import * as feeds from "../../../__mocks__/api/feeds.json";

function createMockHandlers() {
return [
/**
* @param {{ empty?: boolean }} [options] - When `empty` is true an additional
* handler is registered that returns a feed with no nodes, useful to showcase
* the configurable `noFeedText`.
*/
function createMockHandlers(options = {}) {
const handlers = [
http.get("/api/mocks/feeds-json", () => {
// @ts-ignore
return HttpResponse.json(feeds.default || feeds);
}),
];

if (options.empty) {
handlers.push(
http.get("/api/mocks/empty-feeds-json", () =>
HttpResponse.json({ nodes: [] })
)
);
}

return handlers;
}

export { createMockHandlers };
Loading