diff --git a/frontend/components/LinkWithContext/LinkWithContext.tsx b/frontend/components/LinkWithContext/LinkWithContext.tsx index 3a6d291576..4fae121674 100644 --- a/frontend/components/LinkWithContext/LinkWithContext.tsx +++ b/frontend/components/LinkWithContext/LinkWithContext.tsx @@ -16,6 +16,7 @@ interface ILinkWithContextProps { names: string[]; }; className?: string; + disabled?: boolean; } const LinkWithContext = ({ @@ -24,6 +25,7 @@ const LinkWithContext = ({ to, withParams, className, + disabled = false, }: ILinkWithContextProps): JSX.Element => { const classNames = classnames(baseClass, className); @@ -32,6 +34,11 @@ const LinkWithContext = ({ const newParams = pick(currentQueryParams, withParams.names); queryString = buildQueryStringFromParams(newParams); } + + if (disabled) { + return {children}; + } + return ( { const [searchQueryInput, setSearchQueryInput] = useState(defaultValue); @@ -59,6 +61,7 @@ const SearchField = ({ clearButton={clearButton} iconPosition="start" iconSvg={icon} + disabled={disabled} /> diff --git a/frontend/pages/SoftwarePage/SoftwareAddPage/SoftwareAppStore/SoftwareAppStoreAndroid/SoftwareAppStoreAndroid.tsx b/frontend/pages/SoftwarePage/SoftwareAddPage/SoftwareAppStore/SoftwareAppStoreAndroid/SoftwareAppStoreAndroid.tsx index 6c4a020a7d..008f15e179 100644 --- a/frontend/pages/SoftwarePage/SoftwareAddPage/SoftwareAppStore/SoftwareAppStoreAndroid/SoftwareAppStoreAndroid.tsx +++ b/frontend/pages/SoftwarePage/SoftwareAddPage/SoftwareAppStore/SoftwareAppStoreAndroid/SoftwareAppStoreAndroid.tsx @@ -106,6 +106,7 @@ const SoftwareAppStoreAndroid = ({ /> {showPreviewEndUserExperience && ( )} diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/EditSoftwareModal/EditSoftwareModal.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/EditSoftwareModal/EditSoftwareModal.tsx index b6631a41ff..c00edd3115 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/EditSoftwareModal/EditSoftwareModal.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/EditSoftwareModal/EditSoftwareModal.tsx @@ -55,6 +55,9 @@ interface IEditSoftwareModalProps { router: InjectedRouter; openViewYamlModal: () => void; isIosOrIpadosApp?: boolean; + name: string; + displayName: string; + source?: string; } const EditSoftwareModal = ({ @@ -67,6 +70,9 @@ const EditSoftwareModal = ({ router, openViewYamlModal, isIosOrIpadosApp = false, + name, + displayName, + source, }: IEditSoftwareModalProps) => { const { renderFlash } = useContext(NotificationContext); const { config } = useContext(AppContext); @@ -372,6 +378,10 @@ const EditSoftwareModal = ({ )} {showPreviewEndUserExperienceModal && ( diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareSummaryCard/SoftwareSummaryCard.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareSummaryCard/SoftwareSummaryCard.tsx index 6e9025f1d3..95a544128b 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareSummaryCard/SoftwareSummaryCard.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareSummaryCard/SoftwareSummaryCard.tsx @@ -189,6 +189,9 @@ const SoftwareSummaryCard = ({ installerType={installerType} openViewYamlModal={onToggleViewYaml} isIosOrIpadosApp={isIosOrIpadosApp} + name={softwareTitle.name} + displayName={softwareTitle.display_name || softwareTitle.name} + source={softwareTitle.source} /> )} {showEditConfigurationModal && softwareInstaller && teamId && ( diff --git a/frontend/pages/SoftwarePage/components/icons/SoftwareIcon/SoftwareIcon.tsx b/frontend/pages/SoftwarePage/components/icons/SoftwareIcon/SoftwareIcon.tsx index 79c4bdaac3..c9b1332a39 100644 --- a/frontend/pages/SoftwarePage/components/icons/SoftwareIcon/SoftwareIcon.tsx +++ b/frontend/pages/SoftwarePage/components/icons/SoftwareIcon/SoftwareIcon.tsx @@ -29,6 +29,7 @@ const SoftwareIcon = ({ url, uploadedAt, }: ISoftwareIconProps) => { + console.log("name", name, "source", source, "url", url); const classNames = classnames(baseClass, `${baseClass}__${size}`); const [imgFailed, setImgFailed] = useState(false); diff --git a/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/CategoriesEndUserExperienceModal.tsx b/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/CategoriesEndUserExperienceModal.tsx index 6cb4bb5227..8c41ddd719 100644 --- a/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/CategoriesEndUserExperienceModal.tsx +++ b/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/CategoriesEndUserExperienceModal.tsx @@ -1,35 +1,203 @@ -import React from "react"; +/** Mobile preview modal uses a screenshot + * Non-mobile now uses HTML/CSS instead for + * maintainability as the self-selvice UI changes + * + * Currently only shown from the edit UI, though wired through the Add UI + * Users currently can set categories only when editing a curent installer + */ +import React, { useContext } from "react"; + +import { Column } from "react-table"; +import { noop } from "lodash"; +import { AppContext } from "context/app"; +import { IHeaderProps } from "interfaces/datatable_config"; + +import TableContainer from "components/TableContainer"; +import SoftwareNameCell from "components/TableContainer/DataTable/SoftwareNameCell"; import Modal from "components/Modal"; import Button from "components/buttons/Button"; -import CategoriesEndUserExperiencePreview from "../../../../../../assets/images/categories-end-user-experience-preview-570x259@2x.png"; +import Card from "components/Card"; +import SelfServiceHeader from "pages/hosts/details/cards/Software/SelfService/components/SelfServiceHeader"; +import SearchField from "components/forms/fields/SearchField"; +import HeaderCell from "components/TableContainer/DataTable/HeaderCell"; +import CategoriesMenu from "pages/hosts/details/cards/Software/SelfService/components/CategoriesMenu"; +import { CATEGORIES_NAV_ITEMS } from "pages/hosts/details/cards/Software/SelfService/helpers"; + import CategoriesEndUserExperiencePreviewMobile from "../../../../../../assets/images/categories-end-user-experience-preview-mobile@2x.png"; const baseClass = "categories-end-user-experience-preview-modal"; +interface ISoftwareRow { + name: React.ReactNode; +} + +type ITableHeaderProps = IHeaderProps; + +const columns: Column[] = [ + { + Header: (cellProps: ITableHeaderProps) => ( + + ), + accessor: "name", + disableSortBy: true, + }, +]; + +const getData = ( + name: string, + displayName: string, + iconUrl: string | null, + source?: string +): ISoftwareRow[] => [ + { + name: ( + + ), + }, + { + name: ( + + ), + }, + { + name: ( + + ), + }, + { + name: ( + + ), + }, +]; + +const EmptyState = () =>
No software found
; + +interface BasicSoftwareTableProps { + name: string; + displayName: string; + source?: string; + iconUrl?: string | null; +} + +const BasicSoftwareTable = ({ + name, + displayName, + source, + iconUrl = null, +}: BasicSoftwareTableProps) => { + return ( + + columnConfigs={columns} + data={getData(name, displayName, iconUrl, source)} + isLoading={false} + emptyComponent={EmptyState} + showMarkAllPages={false} + isAllPagesSelected={false} + searchable={false} + disablePagination + disableCount + disableTableHeader + /> + ); +}; + interface ICategoriesEndUserExperienceModal { onCancel: () => void; isIosOrIpadosApp?: boolean; + name?: string; + displayName?: string; + iconUrl?: string; + source?: string; } const CategoriesEndUserExperienceModal = ({ onCancel, isIosOrIpadosApp = false, + name = "Software name", + displayName = "Software name", + iconUrl, + source, }: ICategoriesEndUserExperienceModal): JSX.Element => { + const { config } = useContext(AppContext); return ( <> What end users see: -
- Categories end user experience preview -
+ + {isIosOrIpadosApp ? ( +
+ Categories end user experience preview +
+ ) : ( + +
+ + + +
+ + +
+
+ + )}
diff --git a/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/_styles.scss b/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/_styles.scss index 5780a84abf..0f3ee56a5d 100644 --- a/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/_styles.scss +++ b/frontend/pages/SoftwarePage/components/modals/CategoriesEndUserExperienceModal/_styles.scss @@ -14,10 +14,45 @@ .modal-cta-wrap { margin-top: 0; // Defer to new gap styling } + + &__preview-card { + max-height: 300px; + overflow: hidden; + + .card-header__header { + font-size: initial; + } + + &__self-service { + width: 515px; + height: 310px; + @include vertical-card-layout; + } + + .categories-menu { + top: 0; + width: 200px; + } + + .data-table__table { + width: 325px; + } + } + &__table { + display: flex; + flex-direction: row; + } + + &__disabled-overlay { + position: absolute; + width: 540px; + height: 335px; + z-index: 1000; + } } // Pop up preview immediately. -.modal__background:has(.calendar-event-preview-modal) { +.modal__background:has(.categories-end-user-experience-preview-modal) { transition: none; animation: none; } diff --git a/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoriesMenu/CategoriesMenu.tsx b/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoriesMenu/CategoriesMenu.tsx index 8ee4fa5053..1f5cce77fc 100644 --- a/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoriesMenu/CategoriesMenu.tsx +++ b/frontend/pages/hosts/details/cards/Software/SelfService/components/CategoriesMenu/CategoriesMenu.tsx @@ -13,12 +13,15 @@ export interface ICategoriesMenu { categories: ICategory[]; queryParams: SelfServiceQueryParams; className?: string; + /** Used for reusing component on self-service preview */ + readOnly?: boolean; } const CategoriesMenu = ({ categories, queryParams, className, + readOnly = false, }: ICategoriesMenu) => { const wrapperClasses = classNames(baseClass, className); @@ -47,6 +50,7 @@ const CategoriesMenu = ({ category_id: cat.id !== 0 ? cat.id : undefined, }} to={location.pathname} + disabled={readOnly} > diff --git a/frontend/pages/hosts/details/cards/Software/SelfService/components/SelfServiceHeader/SelfServiceHeader.tsx b/frontend/pages/hosts/details/cards/Software/SelfService/components/SelfServiceHeader/SelfServiceHeader.tsx index b0533e639a..0217d0c008 100644 --- a/frontend/pages/hosts/details/cards/Software/SelfService/components/SelfServiceHeader/SelfServiceHeader.tsx +++ b/frontend/pages/hosts/details/cards/Software/SelfService/components/SelfServiceHeader/SelfServiceHeader.tsx @@ -7,23 +7,32 @@ const SelfServiceHeader = ({ variant, }: { contactUrl: string; - variant?: "mobile-header"; -}) => ( - - Install organization-approved apps provided by your IT department.{" "} - {contactUrl && ( - - If you need help,{" "} - - - )} - - } - variant={variant} - /> -); + variant?: "mobile-header" | "preview"; +}) => { + const cardHeaderVariant = variant === "mobile-header" ? variant : undefined; + + return ( + + Install organization-approved apps provided by your IT department.{" "} + {contactUrl && ( + + If you need help,{" "} + + + )} + + } + variant={cardHeaderVariant} + /> + ); +}; export default SelfServiceHeader; diff --git a/frontend/pages/labels/NewLabelPage/NewLabelPage.tsx b/frontend/pages/labels/NewLabelPage/NewLabelPage.tsx index 368b1c71dd..cbe59ba5c0 100644 --- a/frontend/pages/labels/NewLabelPage/NewLabelPage.tsx +++ b/frontend/pages/labels/NewLabelPage/NewLabelPage.tsx @@ -16,8 +16,7 @@ import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants"; // therefore not longer needed anywhere else import { generateTableHeaders } from "pages/labels/components/ManualLabelForm/LabelHostTargetTableConfig"; -// @ts-ignore -import validateQuery from "components/forms/validators/validate_query"; +import { validateQuery } from "components/forms/validators/validate_query"; import { QueryContext } from "context/query"; import { AppContext } from "context/app"; diff --git a/frontend/styles/var/mixins.scss b/frontend/styles/var/mixins.scss index 084854c5f4..7faee828f3 100644 --- a/frontend/styles/var/mixins.scss +++ b/frontend/styles/var/mixins.scss @@ -433,7 +433,9 @@ $max-width: 2560px; height: 32px; border-radius: 4px; - a { + a, + span.link-with-context // Disabled side nav item + { display: flex; align-items: center; height: 100%; @@ -442,8 +444,10 @@ $max-width: 2560px; font-weight: $regular; text-decoration: none; border-bottom: none; - cursor: pointer; + } + a { + cursor: pointer; &:hover { color: $ui-fleet-black-75-over; }