[WEB-756] chore: spreadsheet layout cycle and module feature toggle validation (#4121)

* chore: spreadsheet layout cycle and module feature toggle validation added

* chore: project analytics cycle and module feature toggle validation added
This commit is contained in:
Anmol Singh Bhatia 2024-04-04 15:49:25 +05:30 committed by GitHub
parent 71b73000d2
commit b4cc58d5dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 48 additions and 21 deletions

View File

@ -3,6 +3,7 @@ import { Control, Controller, UseFormSetValue } from "react-hook-form";
import { IAnalyticsParams } from "@plane/types"; import { IAnalyticsParams } from "@plane/types";
// hooks // hooks
import { SelectProject, SelectSegment, SelectXAxis, SelectYAxis } from "@/components/analytics"; import { SelectProject, SelectSegment, SelectXAxis, SelectYAxis } from "@/components/analytics";
import { ANALYTICS_X_AXIS_VALUES } from "@/constants/analytics";
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
// components // components
// types // types
@ -18,7 +19,15 @@ type Props = {
export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => { export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
const { control, setValue, params, fullScreen, isProjectLevel } = props; const { control, setValue, params, fullScreen, isProjectLevel } = props;
const { workspaceProjectIds: workspaceProjectIds } = useProject(); const { workspaceProjectIds: workspaceProjectIds, currentProjectDetails } = useProject();
const analyticsOptions = isProjectLevel
? ANALYTICS_X_AXIS_VALUES.filter((v) => {
if (v.value === "issue_cycle__cycle_id" && !currentProjectDetails?.cycle_view) return false;
if (v.value === "issue_module__module_id" && !currentProjectDetails?.module_view) return false;
return true;
})
: ANALYTICS_X_AXIS_VALUES;
return ( return (
<div <div
@ -64,6 +73,7 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
onChange(val); onChange(val);
}} }}
params={params} params={params}
analyticsOptions={analyticsOptions}
/> />
)} )}
/> />
@ -74,7 +84,7 @@ export const CustomAnalyticsSelectBar: React.FC<Props> = observer((props) => {
name="segment" name="segment"
control={control} control={control}
render={({ field: { value, onChange } }) => ( render={({ field: { value, onChange } }) => (
<SelectSegment value={value} onChange={onChange} params={params} /> <SelectSegment value={value} onChange={onChange} params={params} analyticsOptions={analyticsOptions} />
)} )}
/> />
</div> </div>

View File

@ -3,17 +3,15 @@ import { IAnalyticsParams, TXAxisValues } from "@plane/types";
// ui // ui
import { CustomSelect } from "@plane/ui"; import { CustomSelect } from "@plane/ui";
// types
import { ANALYTICS_X_AXIS_VALUES } from "@/constants/analytics";
// constants
type Props = { type Props = {
value: TXAxisValues | null | undefined; value: TXAxisValues | null | undefined;
onChange: () => void; onChange: () => void;
params: IAnalyticsParams; params: IAnalyticsParams;
analyticsOptions: { value: TXAxisValues; label: string }[];
}; };
export const SelectSegment: React.FC<Props> = ({ value, onChange, params }) => { export const SelectSegment: React.FC<Props> = ({ value, onChange, params, analyticsOptions }) => {
const router = useRouter(); const router = useRouter();
const { cycleId, moduleId } = router.query; const { cycleId, moduleId } = router.query;
@ -22,7 +20,7 @@ export const SelectSegment: React.FC<Props> = ({ value, onChange, params }) => {
value={value} value={value}
label={ label={
<span> <span>
{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === value)?.label ?? ( {analyticsOptions.find((v) => v.value === value)?.label ?? (
<span className="text-custom-text-200">No value</span> <span className="text-custom-text-200">No value</span>
)} )}
</span> </span>
@ -31,7 +29,7 @@ export const SelectSegment: React.FC<Props> = ({ value, onChange, params }) => {
maxHeight="lg" maxHeight="lg"
> >
<CustomSelect.Option value={null}>No value</CustomSelect.Option> <CustomSelect.Option value={null}>No value</CustomSelect.Option>
{ANALYTICS_X_AXIS_VALUES.map((item) => { {analyticsOptions.map((item) => {
if (params.x_axis === item.value) return null; if (params.x_axis === item.value) return null;
if (cycleId && item.value === "issue_cycle__cycle_id") return null; if (cycleId && item.value === "issue_cycle__cycle_id") return null;
if (moduleId && item.value === "issue_module__module_id") return null; if (moduleId && item.value === "issue_module__module_id") return null;

View File

@ -3,18 +3,16 @@ import { IAnalyticsParams, TXAxisValues } from "@plane/types";
// ui // ui
import { CustomSelect } from "@plane/ui"; import { CustomSelect } from "@plane/ui";
// types
import { ANALYTICS_X_AXIS_VALUES } from "@/constants/analytics";
// constants
type Props = { type Props = {
value: TXAxisValues; value: TXAxisValues;
onChange: (val: string) => void; onChange: (val: string) => void;
params: IAnalyticsParams; params: IAnalyticsParams;
analyticsOptions: { value: TXAxisValues; label: string }[];
}; };
export const SelectXAxis: React.FC<Props> = (props) => { export const SelectXAxis: React.FC<Props> = (props) => {
const { value, onChange, params } = props; const { value, onChange, params, analyticsOptions } = props;
const router = useRouter(); const router = useRouter();
const { cycleId, moduleId } = router.query; const { cycleId, moduleId } = router.query;
@ -22,11 +20,11 @@ export const SelectXAxis: React.FC<Props> = (props) => {
return ( return (
<CustomSelect <CustomSelect
value={value} value={value}
label={<span>{ANALYTICS_X_AXIS_VALUES.find((v) => v.value === value)?.label}</span>} label={<span>{analyticsOptions.find((v) => v.value === value)?.label}</span>}
onChange={onChange} onChange={onChange}
maxHeight="lg" maxHeight="lg"
> >
{ANALYTICS_X_AXIS_VALUES.map((item) => { {analyticsOptions.map((item) => {
if (params.segment === item.value) return null; if (params.segment === item.value) return null;
if (cycleId && item.value === "issue_cycle__cycle_id") return null; if (cycleId && item.value === "issue_cycle__cycle_id") return null;
if (moduleId && item.value === "issue_module__module_id") return null; if (moduleId && item.value === "issue_module__module_id") return null;

View File

@ -182,6 +182,7 @@ export const AllIssueLayoutRoot: React.FC = observer(() => {
updateIssue={updateIssue} updateIssue={updateIssue}
canEditProperties={canEditProperties} canEditProperties={canEditProperties}
viewId={globalViewId} viewId={globalViewId}
isWorkspaceLevel
/> />
{/* peek overview */} {/* peek overview */}
<IssuePeekOverview /> <IssuePeekOverview />

View File

@ -8,8 +8,6 @@ import { IIssueDisplayProperties, TIssue } from "@plane/types";
import { ControlLink, Tooltip } from "@plane/ui"; import { ControlLink, Tooltip } from "@plane/ui";
// components // components
import RenderIfVisible from "@/components/core/render-if-visible-HOC"; import RenderIfVisible from "@/components/core/render-if-visible-HOC";
// constants
import { SPREADSHEET_PROPERTY_LIST } from "@/constants/spreadsheet";
// helper // helper
import { cn } from "@/helpers/common.helper"; import { cn } from "@/helpers/common.helper";
// hooks // hooks
@ -37,6 +35,7 @@ interface Props {
isScrolled: MutableRefObject<boolean>; isScrolled: MutableRefObject<boolean>;
containerRef: MutableRefObject<HTMLTableElement | null>; containerRef: MutableRefObject<HTMLTableElement | null>;
issueIds: string[]; issueIds: string[];
spreadsheetColumnsList: (keyof IIssueDisplayProperties)[];
} }
export const SpreadsheetIssueRow = observer((props: Props) => { export const SpreadsheetIssueRow = observer((props: Props) => {
@ -52,6 +51,7 @@ export const SpreadsheetIssueRow = observer((props: Props) => {
isScrolled, isScrolled,
containerRef, containerRef,
issueIds, issueIds,
spreadsheetColumnsList,
} = props; } = props;
const [isExpanded, setExpanded] = useState<boolean>(false); const [isExpanded, setExpanded] = useState<boolean>(false);
@ -81,6 +81,7 @@ export const SpreadsheetIssueRow = observer((props: Props) => {
isScrolled={isScrolled} isScrolled={isScrolled}
isExpanded={isExpanded} isExpanded={isExpanded}
setExpanded={setExpanded} setExpanded={setExpanded}
spreadsheetColumnsList={spreadsheetColumnsList}
/> />
</RenderIfVisible> </RenderIfVisible>
@ -101,6 +102,7 @@ export const SpreadsheetIssueRow = observer((props: Props) => {
isScrolled={isScrolled} isScrolled={isScrolled}
containerRef={containerRef} containerRef={containerRef}
issueIds={issueIds} issueIds={issueIds}
spreadsheetColumnsList={spreadsheetColumnsList}
/> />
))} ))}
</> </>
@ -123,6 +125,7 @@ interface IssueRowDetailsProps {
isScrolled: MutableRefObject<boolean>; isScrolled: MutableRefObject<boolean>;
isExpanded: boolean; isExpanded: boolean;
setExpanded: Dispatch<SetStateAction<boolean>>; setExpanded: Dispatch<SetStateAction<boolean>>;
spreadsheetColumnsList: (keyof IIssueDisplayProperties)[];
} }
const IssueRowDetails = observer((props: IssueRowDetailsProps) => { const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
@ -138,6 +141,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
isScrolled, isScrolled,
isExpanded, isExpanded,
setExpanded, setExpanded,
spreadsheetColumnsList,
} = props; } = props;
// router // router
const router = useRouter(); const router = useRouter();
@ -255,7 +259,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
</ControlLink> </ControlLink>
</td> </td>
{/* Rest of the columns */} {/* Rest of the columns */}
{SPREADSHEET_PROPERTY_LIST.map((property) => ( {spreadsheetColumnsList.map((property) => (
<IssueColumn <IssueColumn
key={property} key={property}
displayProperties={displayProperties} displayProperties={displayProperties}

View File

@ -1,8 +1,6 @@
// ui // ui
import { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types"; import { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types";
import { LayersIcon } from "@plane/ui"; import { LayersIcon } from "@plane/ui";
// types
import { SPREADSHEET_PROPERTY_LIST } from "@/constants/spreadsheet";
// constants // constants
// components // components
import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC"; import { WithDisplayPropertiesHOC } from "../properties/with-display-properties-HOC";
@ -13,10 +11,12 @@ interface Props {
displayFilters: IIssueDisplayFilterOptions; displayFilters: IIssueDisplayFilterOptions;
handleDisplayFilterUpdate: (data: Partial<IIssueDisplayFilterOptions>) => void; handleDisplayFilterUpdate: (data: Partial<IIssueDisplayFilterOptions>) => void;
isEstimateEnabled: boolean; isEstimateEnabled: boolean;
spreadsheetColumnsList: (keyof IIssueDisplayProperties)[];
} }
export const SpreadsheetHeader = (props: Props) => { export const SpreadsheetHeader = (props: Props) => {
const { displayProperties, displayFilters, handleDisplayFilterUpdate, isEstimateEnabled } = props; const { displayProperties, displayFilters, handleDisplayFilterUpdate, isEstimateEnabled, spreadsheetColumnsList } =
props;
return ( return (
<thead className="sticky top-0 left-0 z-[12] border-b-[0.5px] border-custom-border-100"> <thead className="sticky top-0 left-0 z-[12] border-b-[0.5px] border-custom-border-100">
@ -36,7 +36,7 @@ export const SpreadsheetHeader = (props: Props) => {
</span> </span>
</th> </th>
{SPREADSHEET_PROPERTY_LIST.map((property) => ( {spreadsheetColumnsList.map((property) => (
<SpreadsheetHeaderColumn <SpreadsheetHeaderColumn
key={property} key={property}
property={property} property={property}

View File

@ -22,6 +22,7 @@ type Props = {
canEditProperties: (projectId: string | undefined) => boolean; canEditProperties: (projectId: string | undefined) => boolean;
portalElement: React.MutableRefObject<HTMLDivElement | null>; portalElement: React.MutableRefObject<HTMLDivElement | null>;
containerRef: MutableRefObject<HTMLTableElement | null>; containerRef: MutableRefObject<HTMLTableElement | null>;
spreadsheetColumnsList: (keyof IIssueDisplayProperties)[];
}; };
export const SpreadsheetTable = observer((props: Props) => { export const SpreadsheetTable = observer((props: Props) => {
@ -36,6 +37,7 @@ export const SpreadsheetTable = observer((props: Props) => {
updateIssue, updateIssue,
canEditProperties, canEditProperties,
containerRef, containerRef,
spreadsheetColumnsList,
} = props; } = props;
// states // states
@ -83,6 +85,7 @@ export const SpreadsheetTable = observer((props: Props) => {
displayFilters={displayFilters} displayFilters={displayFilters}
handleDisplayFilterUpdate={handleDisplayFilterUpdate} handleDisplayFilterUpdate={handleDisplayFilterUpdate}
isEstimateEnabled={isEstimateEnabled} isEstimateEnabled={isEstimateEnabled}
spreadsheetColumnsList={spreadsheetColumnsList}
/> />
<tbody> <tbody>
{issueIds.map((id) => ( {issueIds.map((id) => (
@ -99,6 +102,7 @@ export const SpreadsheetTable = observer((props: Props) => {
containerRef={containerRef} containerRef={containerRef}
isScrolled={isScrolled} isScrolled={isScrolled}
issueIds={issueIds} issueIds={issueIds}
spreadsheetColumnsList={spreadsheetColumnsList}
/> />
))} ))}
</tbody> </tbody>

View File

@ -4,6 +4,7 @@ import { TIssue, IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@pl
// components // components
import { Spinner } from "@plane/ui"; import { Spinner } from "@plane/ui";
import { SpreadsheetQuickAddIssueForm } from "@/components/issues"; import { SpreadsheetQuickAddIssueForm } from "@/components/issues";
import { SPREADSHEET_PROPERTY_LIST } from "@/constants/spreadsheet";
import { useProject } from "@/hooks/store"; import { useProject } from "@/hooks/store";
import { SpreadsheetTable } from "./spreadsheet-table"; import { SpreadsheetTable } from "./spreadsheet-table";
// types // types
@ -31,6 +32,7 @@ type Props = {
canEditProperties: (projectId: string | undefined) => boolean; canEditProperties: (projectId: string | undefined) => boolean;
enableQuickCreateIssue?: boolean; enableQuickCreateIssue?: boolean;
disableIssueCreation?: boolean; disableIssueCreation?: boolean;
isWorkspaceLevel?: boolean;
}; };
export const SpreadsheetView: React.FC<Props> = observer((props) => { export const SpreadsheetView: React.FC<Props> = observer((props) => {
@ -46,6 +48,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
canEditProperties, canEditProperties,
enableQuickCreateIssue, enableQuickCreateIssue,
disableIssueCreation, disableIssueCreation,
isWorkspaceLevel = false,
} = props; } = props;
// refs // refs
const containerRef = useRef<HTMLTableElement | null>(null); const containerRef = useRef<HTMLTableElement | null>(null);
@ -55,6 +58,14 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
const isEstimateEnabled: boolean = currentProjectDetails?.estimate !== null; const isEstimateEnabled: boolean = currentProjectDetails?.estimate !== null;
const spreadsheetColumnsList = isWorkspaceLevel
? SPREADSHEET_PROPERTY_LIST
: SPREADSHEET_PROPERTY_LIST.filter((property) => {
if (property === "cycle" && !currentProjectDetails?.cycle_view) return false;
if (property === "modules" && !currentProjectDetails?.module_view) return false;
return true;
});
if (!issueIds || issueIds.length === 0) if (!issueIds || issueIds.length === 0)
return ( return (
<div className="grid h-full w-full place-items-center"> <div className="grid h-full w-full place-items-center">
@ -77,6 +88,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
updateIssue={updateIssue} updateIssue={updateIssue}
canEditProperties={canEditProperties} canEditProperties={canEditProperties}
containerRef={containerRef} containerRef={containerRef}
spreadsheetColumnsList={spreadsheetColumnsList}
/> />
</div> </div>
<div className="border-t border-custom-border-100"> <div className="border-t border-custom-border-100">