mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
fix: notes.
This commit is contained in:
@@ -88,15 +88,15 @@ export default function TableHeader() {
|
|||||||
},
|
},
|
||||||
} = useContext(TableContext);
|
} = useContext(TableContext);
|
||||||
|
|
||||||
if (headerLoading && TableHeaderSkeletonRenderer) {
|
|
||||||
return <TableHeaderSkeletonRenderer />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't contiunue if the thead is disabled.
|
// Can't contiunue if the thead is disabled.
|
||||||
if (hideTableHeader) {
|
if (hideTableHeader) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (headerLoading && TableHeaderSkeletonRenderer) {
|
||||||
|
return <TableHeaderSkeletonRenderer />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollSyncPane>
|
<ScrollSyncPane>
|
||||||
<div className="thead">
|
<div className="thead">
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MenuItem, Button } from '@blueprintjs/core';
|
import { MenuItem, Button } from '@blueprintjs/core';
|
||||||
import { FSelect } from '../../../components';
|
import { FSelect } from '../../../components';
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { FSelect } from 'components';
|
|||||||
* @param {*} exactMatch
|
* @param {*} exactMatch
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const projectItemPredicate = (query, project, _index, exactMatch) => {
|
const projectsItemPredicate = (query, project, _index, exactMatch) => {
|
||||||
const normalizedTitle = project.name.toLowerCase();
|
const normalizedTitle = project.name.toLowerCase();
|
||||||
const normalizedQuery = query.toLowerCase();
|
const normalizedQuery = query.toLowerCase();
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ const projectItemPredicate = (query, project, _index, exactMatch) => {
|
|||||||
* @param {*} param1
|
* @param {*} param1
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const projectItemRenderer = (project, { handleClick, modifiers, query }) => {
|
const projectsItemRenderer = (project, { handleClick, modifiers, query }) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
active={modifiers.active}
|
active={modifiers.active}
|
||||||
@@ -41,13 +41,13 @@ const projectItemRenderer = (project, { handleClick, modifiers, query }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const projectSelectProps = {
|
const projectSelectProps = {
|
||||||
itemPredicate: projectItemPredicate,
|
itemPredicate: projectsItemPredicate,
|
||||||
itemRenderer: projectItemRenderer,
|
itemRenderer: projectsItemRenderer,
|
||||||
valueAccessor: 'id',
|
valueAccessor: 'id',
|
||||||
labelAccessor: 'name',
|
labelAccessor: 'name',
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ProjectSelect({ projects, ...rest }) {
|
export function ProjectsSelect({ projects, ...rest }) {
|
||||||
return (
|
return (
|
||||||
<FSelect
|
<FSelect
|
||||||
items={projects}
|
items={projects}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { MenuItem, Button } from '@blueprintjs/core';
|
import { MenuItem, Button } from '@blueprintjs/core';
|
||||||
import { FSelect } from '../../../../../components/Forms';
|
import { FSelect } from 'components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
export * from './ExpenseSelect';
|
export * from './ExpenseSelect';
|
||||||
export * from './ChangeTypesSelect';
|
export * from './ChangeTypesSelect';
|
||||||
export * from './FInputGroupComponent'
|
export * from './TaskSelect';
|
||||||
|
export * from './ProjectsSelect';
|
||||||
|
export * from './FInputGroupComponent';
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ import {
|
|||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
DashboardRowsHeightButton,
|
DashboardRowsHeightButton,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { TransactionSelect } from './components';
|
import { ProjectTransactionsSelect } from './components';
|
||||||
import withSettings from '../../../Settings/withSettings';
|
import withSettings from '../../../Settings/withSettings';
|
||||||
import withSettingsActions from '../../../Settings/withSettingsActions';
|
import withSettingsActions from '../../../Settings/withSettingsActions';
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
import { projectTranslations } from './common';
|
||||||
import { useProjectDetailContext } from './ProjectDetailProvider';
|
import { useProjectDetailContext } from './ProjectDetailProvider';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ function ProjectDetailActionsBar({
|
|||||||
case 'expense':
|
case 'expense':
|
||||||
openDialog('project-expense-form', { projectId });
|
openDialog('project-expense-form', { projectId });
|
||||||
break;
|
break;
|
||||||
case 'estimatedExpense':
|
case 'estimated_expense':
|
||||||
openDialog('estimated-expense-form', { projectId });
|
openDialog('estimated-expense-form', { projectId });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -73,11 +74,8 @@ function ProjectDetailActionsBar({
|
|||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DashboardActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
<TransactionSelect
|
<ProjectTransactionsSelect
|
||||||
transactions={[
|
transactions={projectTranslations}
|
||||||
{ name: 'New Expense', path: 'expense' },
|
|
||||||
{ name: 'New Estimated Expense', path: 'estimatedExpense' },
|
|
||||||
]}
|
|
||||||
onItemSelect={handleNewTransactionBtnClick}
|
onItemSelect={handleNewTransactionBtnClick}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Tabs, Tab } from '@blueprintjs/core';
|
import { Tabs, Tab } from '@blueprintjs/core';
|
||||||
import TimeSheets from './Timesheets';
|
import ProjectTimeSheets from './ProjectTimeSheets';
|
||||||
import Purchases from './Purchases';
|
import ProjectPurchasesTable from './ProjectPurchasesTable';
|
||||||
import Sales from './Sales';
|
import ProjectSalesTable from './ProjectSalesTable';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project detail tabs.
|
* Project detail tabs.
|
||||||
@@ -23,17 +23,17 @@ export default function ProjectDetailTabs() {
|
|||||||
<Tab
|
<Tab
|
||||||
id="timesheet"
|
id="timesheet"
|
||||||
title={intl.get('project_details.label.timesheet')}
|
title={intl.get('project_details.label.timesheet')}
|
||||||
panel={<TimeSheets />}
|
panel={<ProjectTimeSheets />}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
id="purchases"
|
id="purchases"
|
||||||
title={intl.get('project_details.label.purchases')}
|
title={intl.get('project_details.label.purchases')}
|
||||||
panel={<Purchases />}
|
panel={<ProjectPurchasesTable />}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
id="sales"
|
id="sales"
|
||||||
title={intl.get('project_details.label.sales')}
|
title={intl.get('project_details.label.sales')}
|
||||||
panel={<Sales />}
|
panel={<ProjectSalesTable />}
|
||||||
/>
|
/>
|
||||||
<Tab id="journals" title={intl.get('project_details.label.journals')} />
|
<Tab id="journals" title={intl.get('project_details.label.journals')} />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|||||||
@@ -6,33 +6,22 @@ import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
|||||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||||
import { TABLES } from 'common/tables';
|
import { TABLES } from 'common/tables';
|
||||||
import { useMemorizedColumnsWidths } from 'hooks';
|
import { useMemorizedColumnsWidths } from 'hooks';
|
||||||
import { usePurchasesColumns, ActionMenu } from './components';
|
import { ActionMenu } from './components';
|
||||||
|
import { useProjectPurchasesColumns } from './hooks';
|
||||||
import withSettings from '../../../../Settings/withSettings';
|
import withSettings from '../../../../Settings/withSettings';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
const Purchases = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
date: '2022-06-08T22:00:00.000Z',
|
|
||||||
type: 'Invoice',
|
|
||||||
transaction_no: 'Inv-12345',
|
|
||||||
due_date: '2022-06-08T22:00:00.000Z',
|
|
||||||
balance: '$100.00',
|
|
||||||
status: 'Paid',
|
|
||||||
total: '$100.00',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
/**
|
/**
|
||||||
* Purchases DataTable.
|
* Project Purchases DataTable.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function PurchasesTable({
|
function ProjectPurchasesTableRoot({
|
||||||
// #withSettings
|
// #withSettings
|
||||||
purchasesTableSize,
|
purchasesTableSize,
|
||||||
}) {
|
}) {
|
||||||
// Retrieve purchases table columns.
|
// Retrieve purchases table columns.
|
||||||
const columns = usePurchasesColumns();
|
const columns = useProjectPurchasesColumns();
|
||||||
|
|
||||||
// Handle delete purchase.
|
// Handle delete purchase.
|
||||||
const handleDeletePurchase = () => {};
|
const handleDeletePurchase = () => {};
|
||||||
@@ -44,10 +33,7 @@ function PurchasesTable({
|
|||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={Purchases}
|
data={[]}
|
||||||
// loading={}
|
|
||||||
// headerLoading={}
|
|
||||||
// progressBarLoading={}
|
|
||||||
manualSortBy={true}
|
manualSortBy={true}
|
||||||
selectionColumn={true}
|
selectionColumn={true}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
@@ -64,8 +50,8 @@ function PurchasesTable({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default compose(
|
export const ProjectPurchasesTable = compose(
|
||||||
withSettings(({ purchasesSettings }) => ({
|
withSettings(({ purchasesSettings }) => ({
|
||||||
purchasesTableSize: purchasesSettings?.tableSize,
|
purchasesTableSize: purchasesSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
)(PurchasesTable);
|
)(ProjectPurchasesTableRoot);
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Icon } from 'components';
|
||||||
|
import { Menu, MenuItem, Intent } from '@blueprintjs/core';
|
||||||
|
import { safeCallback } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table actions cell.
|
||||||
|
*/
|
||||||
|
export function ActionMenu({ payload: { onDelete }, row: { original } }) {
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
text={intl.get('purchases.action.delete')}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
onClick={safeCallback(onDelete, original)}
|
||||||
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,30 +1,11 @@
|
|||||||
import React from 'react';
|
import { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
import { FormatDateCell, Icon, FormattedMessage as T } from 'components';
|
import { FormatDateCell } from 'components';
|
||||||
import { Menu, MenuItem, Intent } from '@blueprintjs/core';
|
|
||||||
import { safeCallback } from 'utils';
|
|
||||||
|
|
||||||
/**
|
export function useProjectPurchasesColumns() {
|
||||||
* Table actions cell.
|
return useMemo(
|
||||||
*/
|
|
||||||
export function ActionMenu({ payload: { onDelete }, row: { original } }) {
|
|
||||||
return (
|
|
||||||
<Menu>
|
|
||||||
<MenuItem
|
|
||||||
text={intl.get('purchases.action.delete')}
|
|
||||||
intent={Intent.DANGER}
|
|
||||||
onClick={safeCallback(onDelete, original)}
|
|
||||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePurchasesColumns() {
|
|
||||||
return React.useMemo(
|
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
id: 'date',
|
id: 'date',
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { ProjectPurchasesTable } from './ProjectPurchasesTable';
|
||||||
|
import { DashboardContentTable } from 'components';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function ProjectPurchasesTableRoot() {
|
||||||
|
return (
|
||||||
|
<DashboardContentTable>
|
||||||
|
<ProjectPurchasesTable />
|
||||||
|
</DashboardContentTable>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,34 +5,22 @@ import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
|||||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||||
import { TABLES } from 'common/tables';
|
import { TABLES } from 'common/tables';
|
||||||
import { useMemorizedColumnsWidths } from 'hooks';
|
import { useMemorizedColumnsWidths } from 'hooks';
|
||||||
import { useSalesColumns, ActionMenu } from './components';
|
import { ActionMenu } from './components';
|
||||||
|
import { useProjectSalesColumns } from './hooks';
|
||||||
import withSettings from '../../../../Settings/withSettings';
|
import withSettings from '../../../../Settings/withSettings';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
const Sales = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
date: '2022-06-08T22:00:00.000Z',
|
|
||||||
type: 'Invoice',
|
|
||||||
transaction_no: 'Inv-12345',
|
|
||||||
due_date: '2022-06-08T22:00:00.000Z',
|
|
||||||
balance: '$100.00',
|
|
||||||
status: 'Paid',
|
|
||||||
total: '$100.00',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sales DataTable.
|
* Porject sales datatable.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function SalesTable({
|
function ProjectSalesTableRoot({
|
||||||
// #withSettings
|
// #withSettings
|
||||||
salesTableSize,
|
salesTableSize,
|
||||||
}) {
|
}) {
|
||||||
// Retrieve sales table columns.
|
// Retrieve project sales table columns.
|
||||||
const columns = useSalesColumns();
|
const columns = useProjectSalesColumns();
|
||||||
|
|
||||||
// Handle delete sale.
|
// Handle delete sale.
|
||||||
const handleDeleteSale = () => {};
|
const handleDeleteSale = () => {};
|
||||||
@@ -44,10 +32,7 @@ function SalesTable({
|
|||||||
return (
|
return (
|
||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={Sales}
|
data={[]}
|
||||||
// loading={}
|
|
||||||
// headerLoading={}
|
|
||||||
// progressBarLoading={}
|
|
||||||
manualSortBy={true}
|
manualSortBy={true}
|
||||||
selectionColumn={true}
|
selectionColumn={true}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
@@ -64,8 +49,8 @@ function SalesTable({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default compose(
|
export const ProjectSalesTable = compose(
|
||||||
withSettings(({ salesSettings }) => ({
|
withSettings(({ salesSettings }) => ({
|
||||||
salesTableSize: salesSettings?.tableSize,
|
salesTableSize: salesSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
)(SalesTable);
|
)(ProjectSalesTableRoot);
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
import { FormatDateCell, Icon, FormattedMessage as T } from 'components';
|
||||||
|
import { Menu, MenuItem, Intent } from '@blueprintjs/core';
|
||||||
|
import { safeCallback } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table actions cell.
|
||||||
|
*/
|
||||||
|
export function ActionMenu({ payload: { onDelete }, row: { original } }) {
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
text={intl.get('sales.action.delete')}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
onClick={safeCallback(onDelete, original)}
|
||||||
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,30 +1,11 @@
|
|||||||
import React from 'react';
|
import { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
import { FormatDateCell, Icon, FormattedMessage as T } from 'components';
|
import { FormatDateCell } from 'components';
|
||||||
import { Menu, MenuItem, Intent } from '@blueprintjs/core';
|
|
||||||
import { safeCallback } from 'utils';
|
|
||||||
|
|
||||||
/**
|
export function useProjectSalesColumns() {
|
||||||
* Table actions cell.
|
return useMemo(
|
||||||
*/
|
|
||||||
export function ActionMenu({ payload: { onDelete }, row: { original } }) {
|
|
||||||
return (
|
|
||||||
<Menu>
|
|
||||||
<MenuItem
|
|
||||||
text={intl.get('sales.action.delete')}
|
|
||||||
intent={Intent.DANGER}
|
|
||||||
onClick={safeCallback(onDelete, original)}
|
|
||||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSalesColumns() {
|
|
||||||
return React.useMemo(
|
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
id: 'date',
|
id: 'date',
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { ProjectSalesTable } from './ProjectSalesTable';
|
||||||
|
import { DashboardContentTable } from 'components';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project Sales Table.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function ProjectSalesTableRoot() {
|
||||||
|
return (
|
||||||
|
<ProjectSalesContentTable>
|
||||||
|
<ProjectSalesTable />
|
||||||
|
</ProjectSalesContentTable>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectSalesContentTable = styled(DashboardContentTable)``;
|
||||||
@@ -13,10 +13,10 @@ import {
|
|||||||
import { calculateStatus } from 'utils';
|
import { calculateStatus } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timesheets header
|
* Project Timesheets header
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export default function TimesheetsHeader() {
|
export function ProjectTimesheetsHeader() {
|
||||||
return (
|
return (
|
||||||
<DetailFinancialSection>
|
<DetailFinancialSection>
|
||||||
<DetailFinancialCard label={'Project estimate'} value={'3.14'} />
|
<DetailFinancialCard label={'Project estimate'} value={'3.14'} />
|
||||||
@@ -5,42 +5,24 @@ import { DataTable } from 'components';
|
|||||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||||
import { ActionsMenu } from './components';
|
import { ActionsMenu } from './components';
|
||||||
import { useTimesheetColumns } from './hooks';
|
import { useProjectTimesheetColumns } from './hooks';
|
||||||
import { TABLES } from 'common/tables';
|
import { TABLES } from 'common/tables';
|
||||||
import { useMemorizedColumnsWidths } from 'hooks';
|
import { useMemorizedColumnsWidths } from 'hooks';
|
||||||
import withSettings from '../../../../Settings/withSettings';
|
import withSettings from '../../../../Settings/withSettings';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
const Timesheet = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
date: '2022-06-08T22:00:00.000Z',
|
|
||||||
name: 'Lighting',
|
|
||||||
display_name: 'Kyrie Rearden',
|
|
||||||
description: 'Laid paving stones',
|
|
||||||
duration: '12:00',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
date: '2022-06-08T22:00:00.000Z',
|
|
||||||
name: 'Interior Decoration',
|
|
||||||
display_name: 'Project Sherwood',
|
|
||||||
description: 'Laid paving stones',
|
|
||||||
duration: '11:00',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timesheet DataTable.
|
* Timesheet DataTable.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function TimesheetsTable({
|
function ProjectTimesheetsTableRoot({
|
||||||
// #withSettings
|
// #withSettings
|
||||||
timesheetsTableSize,
|
timesheetsTableSize,
|
||||||
}) {
|
}) {
|
||||||
// Retrieve timesheet table columns.
|
// Retrieve project timesheet table columns.
|
||||||
const columns = useTimesheetColumns();
|
const columns = useProjectTimesheetColumns();
|
||||||
|
|
||||||
// Handle delete timesheet.
|
// Handle delete timesheet.
|
||||||
const handleDeleteTimesheet = () => {};
|
const handleDeleteTimesheet = () => {};
|
||||||
@@ -50,9 +32,9 @@ function TimesheetsTable({
|
|||||||
useMemorizedColumnsWidths(TABLES.TIMESHEETS);
|
useMemorizedColumnsWidths(TABLES.TIMESHEETS);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TimesheetDataTable
|
<ProjectTimesheetDataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={Timesheet}
|
data={[]}
|
||||||
manualSortBy={true}
|
manualSortBy={true}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
sticky={true}
|
sticky={true}
|
||||||
@@ -69,13 +51,13 @@ function TimesheetsTable({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default compose(
|
export const ProjectTimesheetsTable = compose(
|
||||||
withSettings(({ timesheetsSettings }) => ({
|
withSettings(({ timesheetsSettings }) => ({
|
||||||
timesheetsTableSize: timesheetsSettings?.tableSize,
|
timesheetsTableSize: timesheetsSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
)(TimesheetsTable);
|
)(ProjectTimesheetsTableRoot);
|
||||||
|
|
||||||
const TimesheetDataTable = styled(DataTable)`
|
const ProjectTimesheetDataTable = styled(DataTable)`
|
||||||
.table {
|
.table {
|
||||||
.thead .tr .th {
|
.thead .tr .th {
|
||||||
.resizer {
|
.resizer {
|
||||||
@@ -88,6 +70,7 @@ const TimesheetDataTable = styled(DataTable)`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.avatar.td {
|
.avatar.td {
|
||||||
|
.cell-inner {
|
||||||
.avatar {
|
.avatar {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #adbcc9;
|
background: #adbcc9;
|
||||||
@@ -112,6 +95,7 @@ const TimesheetDataTable = styled(DataTable)`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.table-size--small {
|
.table-size--small {
|
||||||
.tbody .tr {
|
.tbody .tr {
|
||||||
height: 45px;
|
height: 45px;
|
||||||
@@ -3,9 +3,9 @@ import intl from 'react-intl-universal';
|
|||||||
import { AvatarCell, TimesheetAccessor } from './components';
|
import { AvatarCell, TimesheetAccessor } from './components';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve timesheet list columns columns.
|
* Retrieve project timesheet list columns.
|
||||||
*/
|
*/
|
||||||
export function useTimesheetColumns() {
|
export function useProjectTimesheetColumns() {
|
||||||
return React.useMemo(
|
return React.useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { ProjectTimesheetsTable } from './ProjectTimesheetsTable';
|
||||||
|
import { ProjectTimesheetsHeader } from './ProjectTimesheetsHeader';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project Timesheets.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function ProjectTimeSheets() {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<ProjectTimesheetsHeader />
|
||||||
|
<ProjectTimesheetTableCard>
|
||||||
|
<ProjectTimesheetsTable />
|
||||||
|
</ProjectTimesheetTableCard>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectTimesheetTableCard = styled.div`
|
||||||
|
margin: 22px 32px;
|
||||||
|
border: 1px solid #c8cad0;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #fff;
|
||||||
|
`;
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import PurchasesTable from './PurchasesTable';
|
|
||||||
import { DashboardContentTable } from 'components';
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export default function Purchases() {
|
|
||||||
return (
|
|
||||||
<DashboardContentTable>
|
|
||||||
<PurchasesTable />
|
|
||||||
</DashboardContentTable>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const PurchasesContentTable = styled.div`
|
|
||||||
margin: 22px 20px;
|
|
||||||
border: 1px solid #d2dce2;
|
|
||||||
background: #fff;
|
|
||||||
/* .bigcapital-datatable {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1 0 0;
|
|
||||||
|
|
||||||
.pagination {
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.has-pagination) {
|
|
||||||
padding-bottom: 30px;
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
`;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import SalesTable from './SalesTable';
|
|
||||||
import { DashboardContentTable } from 'components';
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export default function Sales() {
|
|
||||||
return (
|
|
||||||
<SalesContentTable>
|
|
||||||
<SalesTable />
|
|
||||||
</SalesContentTable>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const SalesContentTable = styled(DashboardContentTable)``;
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
import TimesheetsTable from './TimesheetsTable';
|
|
||||||
import TimesheetsHeader from './TimesheetsHeader';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Project Timesheet.
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export default function TimeSheets() {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<TimesheetsHeader />
|
|
||||||
<TimesheetTableCard>
|
|
||||||
<TimesheetsTable />
|
|
||||||
</TimesheetTableCard>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const TimesheetTableCard = styled.div`
|
|
||||||
margin: 22px 32px;
|
|
||||||
border: 1px solid #c8cad0; // #000a1e33 #f0f0f0
|
|
||||||
border-radius: 3px;
|
|
||||||
background: #fff;
|
|
||||||
`;
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
export const projectTranslations = [
|
||||||
|
{ name: intl.get('project_details.new_expenses'), path: 'expense' },
|
||||||
|
{
|
||||||
|
name: intl.get('project_details.new_estimated_expenses'),
|
||||||
|
path: 'estimated_expense',
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -29,7 +29,6 @@ export const FinancialProgressBar = ({ ...rest }) => {
|
|||||||
|
|
||||||
const FinancialSectionWrap = styled.div`
|
const FinancialSectionWrap = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
/* flex-wrap: wrap; */
|
|
||||||
margin: 22px 32px;
|
margin: 22px 32px;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
`;
|
`;
|
||||||
@@ -47,7 +46,6 @@ const FinancialSectionCard = styled.div`
|
|||||||
|
|
||||||
const FinancialSectionCardContent = styled.div`
|
const FinancialSectionCardContent = styled.div`
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
/* flex-direction: column; */
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FinancialCardWrap = styled.div``;
|
const FinancialCardWrap = styled.div``;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { Icon, FormattedMessage as T } from 'components';
|
|||||||
* @param {*} param1
|
* @param {*} param1
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const transactionItemRenderer = (
|
const projectTransactionItemRenderer = (
|
||||||
transaction,
|
transaction,
|
||||||
{ handleClick, modifiers, query },
|
{ handleClick, modifiers, query },
|
||||||
) => {
|
) => {
|
||||||
@@ -29,8 +29,8 @@ const transactionItemRenderer = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const transactionSelectProps = {
|
const projectTransactionSelectProps = {
|
||||||
itemRenderer: transactionItemRenderer,
|
itemRenderer: projectTransactionItemRenderer,
|
||||||
filterable: false,
|
filterable: false,
|
||||||
popoverProps: {
|
popoverProps: {
|
||||||
minimal: true,
|
minimal: true,
|
||||||
@@ -43,13 +43,13 @@ const transactionSelectProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Project transactions select
|
||||||
* @param
|
* @param
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function TransactionSelect({ transactions, ...rest }) {
|
export function ProjectTransactionsSelect({ transactions, ...rest }) {
|
||||||
return (
|
return (
|
||||||
<Select {...transactionSelectProps} items={transactions} {...rest}>
|
<Select {...projectTransactionSelectProps} items={transactions} {...rest}>
|
||||||
<Button
|
<Button
|
||||||
minimal={true}
|
minimal={true}
|
||||||
icon={<Icon icon={'plus'} />}
|
icon={<Icon icon={'plus'} />}
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
export * from './ProjectSelect';
|
export * from './ProjectTransactionsSelect';
|
||||||
export * from './TransactionSelect';
|
|
||||||
export * from './FinancialSection';
|
export * from './FinancialSection';
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const Schema = Yup.object().shape({
|
|||||||
projectDeadline: Yup.date()
|
projectDeadline: Yup.date()
|
||||||
.label(intl.get('project.schema.label.deadline'))
|
.label(intl.get('project.schema.label.deadline'))
|
||||||
.required(),
|
.required(),
|
||||||
projectState: Yup.boolean().label(
|
published: Yup.boolean().label(
|
||||||
intl.get('project.schema.label.project_state'),
|
intl.get('project.schema.label.project_state'),
|
||||||
),
|
),
|
||||||
projectCost: Yup.number().label(
|
projectCost: Yup.number().label(
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const defaultInitialValues = {
|
|||||||
contact: '',
|
contact: '',
|
||||||
projectName: '',
|
projectName: '',
|
||||||
projectDeadline: moment(new Date()).format('YYYY-MM-DD'),
|
projectDeadline: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
projectState: false,
|
published: false,
|
||||||
projectCost: '',
|
projectCost: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ function ProjectFormFields() {
|
|||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
{/*------------ CheckBox -----------*/}
|
{/*------------ CheckBox -----------*/}
|
||||||
<FFormGroup name={'projectState'}>
|
<FFormGroup name={'published'}>
|
||||||
<FCheckbox
|
<FCheckbox
|
||||||
name="projectState"
|
name="published"
|
||||||
label={intl.get('projects.dialog.calculator_expenses')}
|
label={intl.get('projects.dialog.calculator_expenses')}
|
||||||
/>
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
@@ -100,7 +100,7 @@ function ProjectFormFields() {
|
|||||||
<ControlGroup>
|
<ControlGroup>
|
||||||
<InputPrependText text={'USD'} />
|
<InputPrependText text={'USD'} />
|
||||||
<FMoneyInputGroup
|
<FMoneyInputGroup
|
||||||
disabled={values.projectState}
|
disabled={values.published}
|
||||||
name={'project_cost'}
|
name={'project_cost'}
|
||||||
allowDecimals={true}
|
allowDecimals={true}
|
||||||
allowNegativeValue={true}
|
allowNegativeValue={true}
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { MenuItem, Button } from '@blueprintjs/core';
|
|
||||||
import { FSelect } from 'components';
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*}
|
|
||||||
* @param {*} param1
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const taskModalChargeRenderer = (item, { handleClick, modifiers, query }) => {
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
label={item.label}
|
|
||||||
key={item.name}
|
|
||||||
onClick={handleClick}
|
|
||||||
text={item.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const taskModalChargeSelectProps = {
|
|
||||||
itemRenderer: taskModalChargeRenderer,
|
|
||||||
valueAccessor: 'value',
|
|
||||||
labelAccessor: 'name',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param param0
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export function TaskModalChargeSelect({ items, ...rest }) {
|
|
||||||
return (
|
|
||||||
<FSelect
|
|
||||||
{...taskModalChargeSelectProps}
|
|
||||||
{...rest}
|
|
||||||
items={items}
|
|
||||||
input={TaskModalChargeSelectButton}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param param0
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function TaskModalChargeSelectButton({ label }) {
|
|
||||||
return <Button text={label} />;
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
FieldRequiredHint,
|
FieldRequiredHint,
|
||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { ProjectSelect, TaskSelect } from './components';
|
import { TaskSelect, ProjectsSelect } from '../../components';
|
||||||
import { momentFormatter } from 'utils';
|
import { momentFormatter } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,8 +31,8 @@ function ProjectTimeEntryFormFields() {
|
|||||||
labelInfo={<FieldRequiredHint />}
|
labelInfo={<FieldRequiredHint />}
|
||||||
className={classNames('form-group--select-list', Classes.FILL)}
|
className={classNames('form-group--select-list', Classes.FILL)}
|
||||||
>
|
>
|
||||||
<ProjectSelect
|
<ProjectsSelect
|
||||||
name={'tesc'}
|
name={'projectId'}
|
||||||
projects={[]}
|
projects={[]}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
import { MenuItem, Button } from '@blueprintjs/core';
|
|
||||||
import { FSelect } from 'components/Forms';
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} query
|
|
||||||
* @param {*} project
|
|
||||||
* @param {*} _index
|
|
||||||
* @param {*} exactMatch
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const projectItemPredicate = (query, project, _index, exactMatch) => {
|
|
||||||
const normalizedTitle = project.name.toLowerCase();
|
|
||||||
const normalizedQuery = query.toLowerCase();
|
|
||||||
|
|
||||||
if (exactMatch) {
|
|
||||||
return normalizedTitle === normalizedQuery;
|
|
||||||
} else {
|
|
||||||
return `${project.name}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} project
|
|
||||||
* @param {*} param1
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const projectItemRenderer = (project, { handleClick, modifiers, query }) => {
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
active={modifiers.active}
|
|
||||||
disabled={modifiers.disabled}
|
|
||||||
key={project.id}
|
|
||||||
onClick={handleClick}
|
|
||||||
text={project.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const projectSelectProps = {
|
|
||||||
// itemPredicate: projectItemPredicate,
|
|
||||||
itemRenderer: projectItemRenderer,
|
|
||||||
valueAccessor: 'id',
|
|
||||||
labelAccessor: 'name',
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ProjectSelect({ projects, ...rest }) {
|
|
||||||
return (
|
|
||||||
<FSelect
|
|
||||||
items={projects}
|
|
||||||
{...projectSelectProps}
|
|
||||||
{...rest}
|
|
||||||
input={ProjectSelectButton}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ProjectSelectButton({ label }) {
|
|
||||||
return <Button text={label ? label : intl.get('find_or_choose_a_project')} />;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from './ProjectSelect';
|
|
||||||
export * from './TaskSelect';
|
|
||||||
@@ -138,8 +138,8 @@ const ProjectsTable = styled(DataTable)`
|
|||||||
.tr .td {
|
.tr .td {
|
||||||
padding: 0.5rem 0.8rem;
|
padding: 0.5rem 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar.td {
|
.avatar.td {
|
||||||
|
.cell-inner {
|
||||||
.avatar {
|
.avatar {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: #adbcc9;
|
background: #adbcc9;
|
||||||
@@ -163,7 +163,7 @@ const ProjectsTable = styled(DataTable)`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.table-size--small {
|
.table-size--small {
|
||||||
.tbody .tr {
|
.tbody .tr {
|
||||||
height: 45px;
|
height: 45px;
|
||||||
|
|||||||
@@ -175,10 +175,10 @@ const ProjectItemDescription = styled.div`
|
|||||||
const ProjectStatusRoot = styled.div`
|
const ProjectStatusRoot = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
/* justify-content: flex-end; */
|
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ProjectStatusTaskAmount = styled.div`
|
const ProjectStatusTaskAmount = styled.div`
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@@ -198,6 +198,7 @@ const ProjectProgressBar = styled(ProgressBar)`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StatusTag = styled(Tag)`
|
const StatusTag = styled(Tag)`
|
||||||
min-width: 65px;
|
min-width: 65px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -2082,6 +2082,8 @@
|
|||||||
"project_details.label.purchases": "Purchases",
|
"project_details.label.purchases": "Purchases",
|
||||||
"project_details.label.sales": "Sales",
|
"project_details.label.sales": "Sales",
|
||||||
"project_details.label.journals": "Journals",
|
"project_details.label.journals": "Journals",
|
||||||
|
"project_details.new_expenses": "New Expenses",
|
||||||
|
"project_details.new_estimated_expenses": "New Estimated Expenses",
|
||||||
"timesheets.actions.delete_timesheet": "Delete",
|
"timesheets.actions.delete_timesheet": "Delete",
|
||||||
"timesheets.column.date": "Date",
|
"timesheets.column.date": "Date",
|
||||||
"timesheets.column.task": "Task",
|
"timesheets.column.task": "Task",
|
||||||
|
|||||||
Reference in New Issue
Block a user