mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
GT-721-change-schema-regsitry-tab-position
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/10335 GitOrigin-RevId: da2e2f53f85477b80e90dd8179ffde28108679f4
This commit is contained in:
parent
57b471ef03
commit
f386414058
@ -3,6 +3,9 @@ import { Link, RouteComponentProps } from 'react-router';
|
||||
import { isProConsole } from '../../../utils/proConsole';
|
||||
import { useEELiteAccess } from '../../../features/EETrial';
|
||||
import globals from '../../../Globals';
|
||||
import { IconTooltip } from '../../../new-components/Tooltip';
|
||||
import { FaRegMap } from 'react-icons/fa';
|
||||
import { sendTelemetryEvent } from '../../../telemetry';
|
||||
|
||||
type TopNavProps = {
|
||||
location: RouteComponentProps<unknown, unknown>['location'];
|
||||
@ -25,6 +28,12 @@ const TopNav: React.FC<TopNavProps> = ({ location }) => {
|
||||
dataTestVal: 'rest-explorer-link',
|
||||
title: 'REST',
|
||||
},
|
||||
{
|
||||
key: 'schema-registry',
|
||||
link: '/api/schema-registry',
|
||||
dataTestVal: 'schema-registry-link',
|
||||
title: 'Schema Registry',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
@ -68,13 +77,30 @@ const TopNav: React.FC<TopNavProps> = ({ location }) => {
|
||||
: 'border-white hover:border-gray-100'
|
||||
}`}
|
||||
key={section.key}
|
||||
onClick={() => {
|
||||
// Send Telemetry data for Schema Registry tab
|
||||
if (section.key === 'schema-registry') {
|
||||
sendTelemetryEvent({
|
||||
type: 'CLICK_EVENT',
|
||||
data: {
|
||||
id: 'schema-registry-top-nav-tab',
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to={section.link}
|
||||
data-test={section.dataTestVal}
|
||||
className="text-gray-600 font-semibold no-underline hover:text-gray-600 hover:no-underline focus:text-gray-600 focus:no-underline"
|
||||
className="flex text-gray-600 font-semibold no-underline hover:text-gray-600 hover:no-underline focus:text-gray-600 focus:no-underline"
|
||||
>
|
||||
{section.title}
|
||||
{section.key === 'schema-registry' && (
|
||||
<IconTooltip
|
||||
icon={<FaRegMap />}
|
||||
message="Detect breaking and dangerous changes, view schema change history. Keep your GraphQL services safe and reliable! 🚀"
|
||||
/>
|
||||
)}
|
||||
</Link>
|
||||
</div>
|
||||
))
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
|
||||
import { useEELiteAccess } from '../../../features/EETrial';
|
||||
import { getQueryResponseCachingRoute } from '../../../utils/routeUtils';
|
||||
import { isCloudConsole } from '../../../utils/cloudConsole';
|
||||
import { isOpenTelemetrySupported } from '../../../utils/proConsole';
|
||||
|
||||
export interface Metadata {
|
||||
@ -33,8 +32,7 @@ type SectionDataKey =
|
||||
| 'security'
|
||||
| 'monitoring'
|
||||
| 'performance'
|
||||
| 'about'
|
||||
| 'graphql';
|
||||
| 'about';
|
||||
|
||||
const Sidebar: React.FC<SidebarProps> = ({ location, metadata }) => {
|
||||
const eeLiteAccess = useEELiteAccess(globals);
|
||||
@ -47,25 +45,6 @@ const Sidebar: React.FC<SidebarProps> = ({ location, metadata }) => {
|
||||
label: 'Metadata',
|
||||
items: [],
|
||||
};
|
||||
|
||||
if (
|
||||
isCloudConsole(globals) &&
|
||||
(globals.userRole === 'admin' || globals.userRole === 'owner')
|
||||
) {
|
||||
sectionsData.graphql = {
|
||||
key: 'graphql',
|
||||
label: 'GraphQL',
|
||||
items: [
|
||||
{
|
||||
key: 'schema-registry',
|
||||
label: 'Schema Registry (Beta)',
|
||||
route: '/settings/schema-registry',
|
||||
dataTestVal: 'metadata-schema-registry-link',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
sectionsData.metadata.items.push({
|
||||
key: 'actions',
|
||||
label: 'Metadata Actions',
|
||||
|
@ -6,23 +6,19 @@ import { SCHEMA_REGISTRY_FEATURE_NAME } from '../constants';
|
||||
import { FaBell } from 'react-icons/fa';
|
||||
import { IconTooltip } from '../../../new-components/Tooltip';
|
||||
import { AlertsDialog } from './AlertsDialog';
|
||||
import { Badge } from '../../../new-components/Badge';
|
||||
import { SCHEMA_REGISTRY_REF_URL } from '../constants';
|
||||
import { Analytics } from '../../Analytics';
|
||||
import { Analytics, InitializeTelemetry } from '../../Analytics';
|
||||
import { useGetV2Info } from '../hooks/useGetV2Info';
|
||||
import { telemetryUserEventsTracker } from '../../../telemetry';
|
||||
|
||||
const SchemaRegistryHeader: React.VFC = () => {
|
||||
const [isAlertModalOpen, setIsAlertModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex flex-col w-full pl-12 mb-2">
|
||||
<div className="flex mb-xs mt-md w-full">
|
||||
<h1 className="inline-block text-xl font-semibold mr-2 text-slate-900">
|
||||
GraphQL Schema Registry
|
||||
</h1>
|
||||
<Badge className="mx-2" color="blue">
|
||||
BETA
|
||||
</Badge>
|
||||
<Analytics name="data-schema-registry-alerts-btn">
|
||||
<div
|
||||
className="flex text-lg mt-2 mx-2 cursor-pointer"
|
||||
@ -36,14 +32,6 @@ const SchemaRegistryHeader: React.VFC = () => {
|
||||
</div>
|
||||
</Analytics>
|
||||
</div>
|
||||
<a
|
||||
className="text-muted w-auto mb-xs text-md"
|
||||
href={SCHEMA_REGISTRY_REF_URL}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
What is Schema Registry?
|
||||
</a>
|
||||
<span className="text-muted text-md mb-2 italic">
|
||||
GraphQL Schema Registry changes will only be retained for 14 days.
|
||||
</span>
|
||||
@ -96,8 +84,9 @@ export const SchemaRegistryContainer: React.VFC<
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="p-4 flex flex-col w-full">
|
||||
<div className="flex flex-col w-[80%] pl-10 ml-10 justify-center">
|
||||
<SchemaRegistryHeader />
|
||||
<InitializeTelemetry tracker={telemetryUserEventsTracker} skip={false} />
|
||||
<SchemaRegistryBody
|
||||
hasFeatureAccess={hasFeatureAccess}
|
||||
schemaId={schemaId}
|
||||
|
@ -4,42 +4,18 @@ import { useGetSchema } from '../hooks/useGetSchema';
|
||||
import { Tabs } from '../../../new-components/Tabs';
|
||||
import { IconTooltip } from '../../../new-components/Tooltip';
|
||||
import { SchemaRow } from './SchemaRow';
|
||||
import { ChangeSummary } from './ChangeSummary';
|
||||
import {
|
||||
findIfSubStringExists,
|
||||
schemaTransformFn,
|
||||
getPublishTime,
|
||||
} from '../utils';
|
||||
import { Link } from 'react-router';
|
||||
import { RoleBasedSchema, Schema } from '../types';
|
||||
import {
|
||||
FaHome,
|
||||
FaAngleRight,
|
||||
FaFileImport,
|
||||
FaSearch,
|
||||
FaShareAlt,
|
||||
} from 'react-icons/fa';
|
||||
import { FaSearch, FaShareAlt } from 'react-icons/fa';
|
||||
import { Input } from '../../../new-components/Form';
|
||||
import AceEditor from 'react-ace';
|
||||
import { SearchableSelect } from '../../../components/Common';
|
||||
import { Analytics } from '../../Analytics';
|
||||
|
||||
export const Breadcrumbs = () => (
|
||||
<div className="flex items-center space-x-xs mb-4">
|
||||
<Link
|
||||
to="/settings/schema-registry"
|
||||
className="cursor-pointer flex items-center text-muted hover:text-gray-900"
|
||||
>
|
||||
<FaHome className="mr-1.5" />
|
||||
<span className="text-sm">Schema</span>
|
||||
</Link>
|
||||
<FaAngleRight className="text-muted" />
|
||||
<div className="cursor-pointer flex items-center text-yellow-500">
|
||||
<FaFileImport className="mr-1.5" />
|
||||
<span className="text-sm">Roles</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
interface SchemaChangeDetailsProps {
|
||||
schemaId: string;
|
||||
}
|
||||
@ -113,16 +89,17 @@ const SchemasDetails: React.VFC<{
|
||||
/>
|
||||
<div className="px-4 mb-2">
|
||||
<div className="flex mt-4">
|
||||
<div className="flex-col ">
|
||||
<div className="flex items-center">
|
||||
<p className="font-bold text-gray-500 py-2">Published</p>
|
||||
<div className="flex items-center ">
|
||||
<p className="font-bold text-gray-500 py-2">Published: </p>
|
||||
|
||||
<div className="flex items-center ml-2 font-semibold text-gray-600">
|
||||
<span>{getPublishTime(schema.created_at)}</span>
|
||||
<IconTooltip message="The time at which this GraphQL schema was generated" />
|
||||
</div>
|
||||
<span>{getPublishTime(schema.created_at)}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-around ml-auto w-1/2">
|
||||
<div className="flex-col">
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center mt-4">
|
||||
<p className="font-bold text-gray-500 py-2">Hash</p>
|
||||
<IconTooltip message="Hash of the GraphQL Schema SDL. Hash for two identical schema is identical." />
|
||||
</div>
|
||||
@ -263,65 +240,64 @@ export const ChangesView: React.VFC<{
|
||||
changesList.filter(c => c.criticality.level === 'NON_BREAKING');
|
||||
|
||||
const showBreakingChanges =
|
||||
!selectedChangeLevel || selectedChangeLevel === 'breaking';
|
||||
(!selectedChangeLevel || selectedChangeLevel === 'breaking') &&
|
||||
!!breakingChanges?.length;
|
||||
const showDangerousChanges =
|
||||
!selectedChangeLevel || selectedChangeLevel === 'dangerous';
|
||||
(!selectedChangeLevel || selectedChangeLevel === 'dangerous') &&
|
||||
!!dangerousChanges?.length;
|
||||
const showSafeChanges =
|
||||
!selectedChangeLevel || selectedChangeLevel === 'safe';
|
||||
(!selectedChangeLevel || selectedChangeLevel === 'safe') &&
|
||||
!!safeChanges?.length;
|
||||
|
||||
const onFilterChange = (op: Option) => {
|
||||
setSelectedChangeLevel(op.value);
|
||||
};
|
||||
return (
|
||||
<div className="flex-col">
|
||||
<div className="flex-col">
|
||||
<div className="font-semibold text-lg mb-8 mt-8 text-gray-500">
|
||||
Change Summary
|
||||
</div>
|
||||
<div className="mr-8">
|
||||
<ChangeSummary changes={changes} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full border-b border-gray-300 my-8" />
|
||||
<div className="flex w-full mb-4 justify-between items-center">
|
||||
<div className="flex w-full mt-4 mb-4 justify-between items-center">
|
||||
<div className="flex font-semibold text-lg text-gray-500">Changes</div>
|
||||
<div className="flex block w-[50%]">
|
||||
<div className="flex w-[50%]">
|
||||
<div className="flex w-full">
|
||||
<div className="px-2 w-1/2">
|
||||
<SearchableSelect
|
||||
options={[
|
||||
{
|
||||
value: 'breaking',
|
||||
label: 'Breaking',
|
||||
},
|
||||
{
|
||||
value: 'dangerous',
|
||||
label: 'Dangerous',
|
||||
},
|
||||
{
|
||||
value: 'safe',
|
||||
label: 'Safe',
|
||||
},
|
||||
]}
|
||||
onChange={op => {
|
||||
onFilterChange(op as Option);
|
||||
}}
|
||||
filterOption="prefix"
|
||||
placeholder="Filter"
|
||||
isClearable={true}
|
||||
/>
|
||||
</div>
|
||||
<div className="pr-2 w-1/2">
|
||||
<label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
name="search"
|
||||
icon={<FaSearch />}
|
||||
iconPosition="start"
|
||||
onChange={handleSearch}
|
||||
<Analytics name="schema-registry-schema-change-details-filter">
|
||||
<SearchableSelect
|
||||
options={[
|
||||
{
|
||||
value: 'breaking',
|
||||
label: 'Breaking',
|
||||
},
|
||||
{
|
||||
value: 'dangerous',
|
||||
label: 'Dangerous',
|
||||
},
|
||||
{
|
||||
value: 'safe',
|
||||
label: 'Safe',
|
||||
},
|
||||
]}
|
||||
onChange={op => {
|
||||
onFilterChange(op as Option);
|
||||
}}
|
||||
filterOption="prefix"
|
||||
placeholder="Filter"
|
||||
isClearable={true}
|
||||
/>
|
||||
</label>
|
||||
</Analytics>
|
||||
</div>
|
||||
|
||||
<div className="pr-2 w-1/2">
|
||||
<Analytics name="schema-registry-schema-change-details-search">
|
||||
<label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
name="search"
|
||||
icon={<FaSearch />}
|
||||
iconPosition="start"
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</label>
|
||||
</Analytics>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -329,31 +305,27 @@ export const ChangesView: React.VFC<{
|
||||
|
||||
{showBreakingChanges && (
|
||||
<div>
|
||||
<div className="font-semibold text-md text-gray-500 mt-4">
|
||||
<div className="flex items-center font-semibold text-md text-gray-500 mt-4">
|
||||
Breaking
|
||||
</div>
|
||||
<div className="text-sm text-gray-600 pb-2">
|
||||
Content for What is breaking on schema registry
|
||||
<IconTooltip message="Breaking changes due the schema change" />
|
||||
</div>
|
||||
<ChangesTable changes={breakingChanges} level="breaking" />
|
||||
</div>
|
||||
)}
|
||||
{showDangerousChanges && (
|
||||
{showDangerousChanges && dangerousChanges && (
|
||||
<div>
|
||||
<div className="font-semibold text-md text-gray-500 mt-4">
|
||||
<div className="flex items-center font-semibold text-md text-gray-500 mt-4">
|
||||
Dangerous
|
||||
</div>
|
||||
<div className="text-sm text-gray-600 pb-2">
|
||||
Content for What is dangerous on schema registry
|
||||
<IconTooltip message="Dangerous changes due the schema change" />
|
||||
</div>
|
||||
<ChangesTable changes={dangerousChanges} level="dangerous" />
|
||||
</div>
|
||||
)}
|
||||
{showSafeChanges && (
|
||||
{showSafeChanges && safeChanges && (
|
||||
<div>
|
||||
<div className="font-semibold text-md text-gray-500 mt-4">Safe</div>
|
||||
<div className="text-sm text-gray-600 pb-2">
|
||||
Content for What is safe on schema registry
|
||||
<div className="flex items-center font-semibold text-md text-gray-500 mt-4">
|
||||
Safe
|
||||
<IconTooltip message="Safe changes due the schema change" />
|
||||
</div>
|
||||
<ChangesTable changes={safeChanges} level="safe" />
|
||||
</div>
|
||||
@ -385,7 +357,7 @@ const ChangesTable: React.FC<ChangesTableProps> = ({ changes, level }) => {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{changes && changes.length ? (
|
||||
{changes &&
|
||||
changes.map((change, index) => (
|
||||
<tr
|
||||
className={`${textColor[level]} border border-neutral-200 p-2`}
|
||||
@ -393,12 +365,7 @@ const ChangesTable: React.FC<ChangesTableProps> = ({ changes, level }) => {
|
||||
>
|
||||
<td className="pl-2">{change.message}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td className="pl-2">{`No ${level} changes`}</td>
|
||||
</tr>
|
||||
)}
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@ import AceEditor from 'react-ace';
|
||||
export const Breadcrumbs = () => (
|
||||
<div className="flex items-center space-x-xs mb-4">
|
||||
<Link
|
||||
to="/settings/schema-registry"
|
||||
to="/api/schema-registry"
|
||||
className="cursor-pointer flex items-center text-muted hover:text-gray-900"
|
||||
>
|
||||
<FaHome className="mr-1.5" />
|
||||
|
@ -78,7 +78,7 @@ export const SchemaRegistryHome: React.FC<SchemaRegistryHomeProps> = props => {
|
||||
if (schemaRoleID === EMPTY_UUID_STRING) {
|
||||
if (latestAdminRoleID) {
|
||||
setSelectedRoleID(latestAdminRoleID);
|
||||
dispatch(_push(`/settings/schema-registry/${latestAdminRoleID}`));
|
||||
dispatch(_push(`/api/schema-registry/${latestAdminRoleID}`));
|
||||
}
|
||||
} else {
|
||||
setSelectedRoleID(schemaRoleID);
|
||||
@ -88,7 +88,7 @@ export const SchemaRegistryHome: React.FC<SchemaRegistryHomeProps> = props => {
|
||||
useEffect(() => {
|
||||
if (latestAdminRoleID) {
|
||||
setSelectedRoleID(latestAdminRoleID);
|
||||
dispatch(_push(`/settings/schema-registry/${latestAdminRoleID}`));
|
||||
dispatch(_push(`/api/schema-registry/${latestAdminRoleID}`));
|
||||
}
|
||||
setSearchParam(pageNo);
|
||||
}, [latestAdminRoleID, pageNo]);
|
||||
@ -118,8 +118,8 @@ export const SchemaRegistryHome: React.FC<SchemaRegistryHomeProps> = props => {
|
||||
fetchSchemasResponse.response
|
||||
);
|
||||
return (
|
||||
<div className="flex w-full">
|
||||
<div className="w-1/4">
|
||||
<div className="flex w-[80%] justify-center">
|
||||
<div className="w-[20%]">
|
||||
<SchemaChangeList
|
||||
schemas={schemaList}
|
||||
urlSchemaCard={URLSchemaCard}
|
||||
@ -172,27 +172,33 @@ export const SchemaChangeList: React.VFC<{
|
||||
return (
|
||||
<div className="overflow-x-auto rounded-md border-neutral-200 bg-white border mr-sm">
|
||||
<div className="w-full flex bg-gray-100 px-4 py-2">
|
||||
<div className="flex text-base w-[69%] justify-start">
|
||||
<div className="flex text-base w-[50%] justify-start">
|
||||
<span className="text-sm font-bold">PUBLISHED SCHEMA</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col w-full">
|
||||
{schemas.length ? (
|
||||
<div className="mb-md">
|
||||
{schemaList.map((schema, index) => (
|
||||
<SchemaCard
|
||||
cardKey={index}
|
||||
openSchemaCardIndex={openSchemaCardIndex}
|
||||
selectedRoleID={selectedRoleID}
|
||||
createdAt={schema.created_at}
|
||||
roles={schema.roles}
|
||||
entryHash={schema.entry_hash}
|
||||
tags={schema.tags}
|
||||
dispatch={dispatch}
|
||||
handleClick={() => setIsOpenSchemaCardIndex(index)}
|
||||
/>
|
||||
))}
|
||||
<div className="flex w-full justify-center items-center">
|
||||
<div
|
||||
style={{ maxHeight: '80vh' }}
|
||||
className={`flex flex-col w-full max-h-400px overflow-y-scroll`}
|
||||
>
|
||||
{schemaList.map((schema, index) => (
|
||||
<SchemaCard
|
||||
cardKey={index}
|
||||
openSchemaCardIndex={openSchemaCardIndex}
|
||||
selectedRoleID={selectedRoleID}
|
||||
createdAt={schema.created_at}
|
||||
roles={schema.roles}
|
||||
entryHash={schema.entry_hash}
|
||||
tags={schema.tags}
|
||||
dispatch={dispatch}
|
||||
handleClick={() => setIsOpenSchemaCardIndex(index)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex w-full justify-center items-center mt-2">
|
||||
<button
|
||||
className="btn btn-primary items-center max-w-full justify-center inline-flex text-sm font-sans font-semibold border rounded shadow-sm focus-visible:outline-none h-btn px-sm mx-1 disabled:border-gray-300 disabled:opacity-60 disabled:cursor-not-allowed"
|
||||
disabled={pageNumber === 0}
|
||||
@ -281,7 +287,8 @@ const SchemaCard: React.VFC<{
|
||||
handleClick,
|
||||
} = props;
|
||||
const [isTagModalOpen, setIsTagModalOpen] = React.useState(false);
|
||||
const [isRolesMenuOpen, setIsRolesMenuOpen] = useState(false);
|
||||
const [isCurrentCardOpen, setIsCurrentCardOpen] = useState(false);
|
||||
|
||||
const [tagsList, setTagsList] = React.useState<SchemaRegistryTag[]>(tags);
|
||||
const onRemoveTag = (id: string) => {
|
||||
const filteredTags = tagsList.filter(
|
||||
@ -289,92 +296,128 @@ const SchemaCard: React.VFC<{
|
||||
);
|
||||
setTagsList(filteredTags);
|
||||
};
|
||||
const adminIndex = roles.findIndex(role => role.role === 'admin');
|
||||
|
||||
// If "admin" is not at the 0 index, move it there
|
||||
if (adminIndex !== 0 && adminIndex !== -1) {
|
||||
const adminRole = roles.splice(adminIndex, 1)[0];
|
||||
roles.unshift(adminRole);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
setTagsList(tags);
|
||||
}, [tags]);
|
||||
React.useEffect(() => {
|
||||
setIsRolesMenuOpen(cardKey === openSchemaCardIndex);
|
||||
setIsCurrentCardOpen(cardKey === openSchemaCardIndex);
|
||||
}, [cardKey, openSchemaCardIndex]);
|
||||
const handleRoleClick = (roleBasedChange: Role) => {
|
||||
dispatch(_push(`/settings/schema-registry/${roleBasedChange.id}`));
|
||||
console.log('click');
|
||||
dispatch(_push(`/api/schema-registry/${roleBasedChange.id}`));
|
||||
};
|
||||
|
||||
const defaultShowAllRoles = isCurrentCardOpen || roles.length <= 3;
|
||||
const RolesList = defaultShowAllRoles ? roles : roles.slice(0, 3);
|
||||
return (
|
||||
<div
|
||||
className="w-full flex flex-col px-4 bg-white rounded"
|
||||
onClick={handleClick}
|
||||
className={`w-full flex flex-col px-4 bg-white rounded mb-1`}
|
||||
onClick={() => {
|
||||
if (!roles.some(role => role.id === selectedRoleID)) {
|
||||
dispatch(_push(`/api/schema-registry/${roles[0].id}`));
|
||||
}
|
||||
handleClick();
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col mt-2 justify-between h-full">
|
||||
<div className="flex text-gray-600 text-sm justify-start">
|
||||
<div
|
||||
className={`mt-2 ${
|
||||
isCurrentCardOpen ? 'bg-gray-100' : ' bg-white'
|
||||
} hover:bg-gray-100 `}
|
||||
>
|
||||
<div className="flex mt-1 mb-2 text-gray-600 text-sm items-center justify-start h-full px-2">
|
||||
<span>{getPublishTime(createdAt)}</span>
|
||||
<span>
|
||||
<Analytics name="schema-registry-add-tag-btn">
|
||||
{isTagModalOpen && (
|
||||
<AddSchemaRegistryTagDialog
|
||||
tagsList={tagsList}
|
||||
setTagsList={setTagsList}
|
||||
entryHash={entryHash}
|
||||
onClose={() => {
|
||||
setIsTagModalOpen(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
<div className="flex flex-nowrap items-center justify-start ">
|
||||
{tagsList &&
|
||||
tagsList.map(schemaRegistryTag => (
|
||||
<div className="mx-1 ">
|
||||
<SchemaTag
|
||||
schemaRegistryTag={schemaRegistryTag}
|
||||
onRemove={onRemoveTag}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<div className="ml-1" onClick={() => setIsTagModalOpen(true)}>
|
||||
<span>
|
||||
<IconTooltip
|
||||
message="Add a Tag"
|
||||
icon={<FaPlusCircle />}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Analytics>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={`flex font-semibold text-md justify-end hover:text-gray-600 ${
|
||||
isRolesMenuOpen ? 'text-gray-600' : 'text-gray-400'
|
||||
} cursor-pointer`}
|
||||
className={`flex flex-col justify-start w-full pt-auto ${
|
||||
isCurrentCardOpen ? 'bg-gray-100' : ''
|
||||
} rounded `}
|
||||
>
|
||||
{roles.length} {roles.length === 1 ? 'Role' : 'Roles'}
|
||||
<span className="mr-1">{<FaChevronDown />}</span>
|
||||
</div>
|
||||
</div>
|
||||
{isRolesMenuOpen && (
|
||||
<div className="w-full pt-auto">
|
||||
<div className="text-sm text-gray-500 font-bold mb-3">
|
||||
{roles.length === 1 ? 'ROLE' : 'ROLES'}
|
||||
<div className="text-sm text-gray-500 font-bold mb-1 px-2">
|
||||
{roles.length} {roles.length === 1 ? 'ROLE' : 'ROLES'}
|
||||
</div>
|
||||
{roles.map((roleBasedChange, index) => (
|
||||
<div
|
||||
className={`flex w-full p-2 ${
|
||||
roleBasedChange.id === selectedRoleID ? 'bg-gray-100' : ''
|
||||
} rounded hover:bg-gray-200`}
|
||||
onClick={() => {
|
||||
handleRoleClick(roleBasedChange);
|
||||
}}
|
||||
key={index}
|
||||
>
|
||||
<div className="flex items-center justify-between w-full rounded">
|
||||
<div className="text-base rounded cursor-pointer">
|
||||
<p className="text-sm text-teal-800 font-bold bg-gray-200 px-1 rounded">
|
||||
{CapitalizeFirstLetter(roleBasedChange.role)}
|
||||
</p>
|
||||
<div>
|
||||
{RolesList.map((roleBasedChange, index) => (
|
||||
<div
|
||||
className={`flex w-full px-2 py-1 ${
|
||||
isCurrentCardOpen && roleBasedChange.id === selectedRoleID
|
||||
? 'bg-gray-200'
|
||||
: ''
|
||||
} rounded hover:bg-gray-200`}
|
||||
onClick={() => {
|
||||
handleRoleClick(roleBasedChange);
|
||||
}}
|
||||
key={index}
|
||||
>
|
||||
<div className="flex items-center justify-between w-full rounded">
|
||||
<div className="text-base rounded cursor-pointer">
|
||||
<p className="text-sm text-teal-800 font-bold bg-gray-200 px-1 rounded">
|
||||
{CapitalizeFirstLetter(roleBasedChange.role)}
|
||||
</p>
|
||||
</div>
|
||||
<FaChevronRight />
|
||||
</div>
|
||||
<FaChevronRight />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{isTagModalOpen && (
|
||||
<AddSchemaRegistryTagDialog
|
||||
tagsList={tagsList}
|
||||
setTagsList={setTagsList}
|
||||
entryHash={entryHash}
|
||||
onClose={() => {
|
||||
setIsTagModalOpen(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-nowrap items-center justify-start mt-2">
|
||||
{tagsList &&
|
||||
tagsList.map(schemaRegistryTag => (
|
||||
<div className="mr-2 ">
|
||||
<SchemaTag
|
||||
schemaRegistryTag={schemaRegistryTag}
|
||||
onRemove={onRemoveTag}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<Analytics name="schema-registry-add-tag-btn">
|
||||
<div
|
||||
className="mt-[7px] ml-[-6px] pb-2"
|
||||
onClick={() => setIsTagModalOpen(true)}
|
||||
>
|
||||
<span>
|
||||
<IconTooltip message="Add a Tag" icon={<FaPlusCircle />} />
|
||||
</span>
|
||||
))}
|
||||
{!defaultShowAllRoles && (
|
||||
<Analytics name="schema-registry-see-more-roles-btn">
|
||||
<div
|
||||
className="flex justify-center items-center cursor-pointer text-base hover:bg-gray-200 pt-1"
|
||||
//here there is no need for onClick as clicking anywhere on a schemaCard sets the schemaCard as open and defaultShowAllRoles will be set to true
|
||||
>
|
||||
<span className="text-gray font-semibold">
|
||||
See More Roles
|
||||
</span>
|
||||
<FaChevronDown />
|
||||
</div>
|
||||
</Analytics>
|
||||
)}
|
||||
</div>
|
||||
</Analytics>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full border-b border-gray-300 my-2"></div>
|
||||
<div className="flex w-full border-b border-gray-300 my-1"></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -3,6 +3,7 @@ import React from 'react';
|
||||
import { Link, RouteComponentProps } from 'react-router';
|
||||
import { FaCheckCircle, FaTimesCircle } from 'react-icons/fa';
|
||||
import { LocationDescriptor } from 'history';
|
||||
import { sendTelemetryEvent } from '../../telemetry';
|
||||
|
||||
export type NavigationSidebarItem = {
|
||||
key: string;
|
||||
@ -50,6 +51,17 @@ export const NavigationSidebar = ({
|
||||
? 'text-amber-500'
|
||||
: 'text-muted'
|
||||
)}
|
||||
onClick={() => {
|
||||
// Check if section.key is "schema-registry" and trigger telemetry event
|
||||
if (item.key === 'schema-registry') {
|
||||
sendTelemetryEvent({
|
||||
type: 'CLICK_EVENT',
|
||||
data: {
|
||||
id: 'schema-registry-settings-btn',
|
||||
},
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</div>
|
||||
|
@ -346,6 +346,11 @@ const routes = store => {
|
||||
<Route path="details/:name" component={RestEndpointDetailsPage} />
|
||||
<Route path="edit/:name" component={CreateRestView} />
|
||||
</Route>
|
||||
<Route path="schema-registry" component={SchemaRegistryContainer} />
|
||||
<Route
|
||||
path="schema-registry/:id"
|
||||
component={SchemaRegistryContainer}
|
||||
/>
|
||||
<Route path="allow-list">
|
||||
<IndexRedirect to="detail" />
|
||||
<Route
|
||||
|
Loading…
Reference in New Issue
Block a user