Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Mike Cao 2023-07-07 20:39:56 -07:00
commit f9d09c8b54
17 changed files with 108 additions and 69 deletions

View file

@ -15,6 +15,7 @@ export const labels = defineMessages({
password: { id: 'label.password', defaultMessage: 'Password' }, password: { id: 'label.password', defaultMessage: 'Password' },
role: { id: 'label.role', defaultMessage: 'Role' }, role: { id: 'label.role', defaultMessage: 'Role' },
user: { id: 'label.user', defaultMessage: 'User' }, user: { id: 'label.user', defaultMessage: 'User' },
viewOnly: { id: 'label.view-only', defaultMessage: 'View only' },
admin: { id: 'label.admin', defaultMessage: 'Administrator' }, admin: { id: 'label.admin', defaultMessage: 'Administrator' },
confirm: { id: 'label.confirm', defaultMessage: 'Confirm' }, confirm: { id: 'label.confirm', defaultMessage: 'Confirm' },
details: { id: 'label.details', defaultMessage: 'Details' }, details: { id: 'label.details', defaultMessage: 'Details' },

View file

@ -7,6 +7,7 @@ import PasswordChangeButton from './PasswordChangeButton';
import useUser from 'hooks/useUser'; import useUser from 'hooks/useUser';
import useMessages from 'hooks/useMessages'; import useMessages from 'hooks/useMessages';
import useConfig from 'hooks/useConfig'; import useConfig from 'hooks/useConfig';
import { ROLES } from 'lib/constants';
export function ProfileDetails() { export function ProfileDetails() {
const { user } = useUser(); const { user } = useUser();
@ -19,12 +20,24 @@ export function ProfileDetails() {
const { username, role } = user; const { username, role } = user;
const renderRole = value => {
if (value === ROLES.user) {
return formatMessage(labels.user);
}
if (value === ROLES.admin) {
return formatMessage(labels.admin);
}
if (value === ROLES.viewOnly) {
return formatMessage(labels.viewOnly);
}
return formatMessage(labels.unknown);
};
return ( return (
<Form> <Form>
<FormRow label={formatMessage(labels.username)}>{username}</FormRow> <FormRow label={formatMessage(labels.username)}>{username}</FormRow>
<FormRow label={formatMessage(labels.role)}> <FormRow label={formatMessage(labels.role)}>{renderRole(role)}</FormRow>
{formatMessage(labels[role] || labels.unknown)}
</FormRow>
{!cloudMode && ( {!cloudMode && (
<FormRow label={formatMessage(labels.password)}> <FormRow label={formatMessage(labels.password)}>
<PasswordChangeButton /> <PasswordChangeButton />

View file

@ -9,8 +9,11 @@ import Icons from 'components/icons';
import TeamJoinForm from './TeamJoinForm'; import TeamJoinForm from './TeamJoinForm';
import useApi from 'hooks/useApi'; import useApi from 'hooks/useApi';
import useMessages from 'hooks/useMessages'; import useMessages from 'hooks/useMessages';
import { ROLES } from 'lib/constants';
import useUser from 'hooks/useUser';
export default function TeamsList() { export default function TeamsList() {
const { user } = useUser();
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const [update, setUpdate] = useState(0); const [update, setUpdate] = useState(0);
const { get, useQuery } = useApi(); const { get, useQuery } = useApi();
@ -48,17 +51,21 @@ export default function TeamsList() {
); );
const createButton = ( const createButton = (
<ModalTrigger> <>
<Button variant="primary"> {user.role !== ROLES.viewOnly && (
<Icon> <ModalTrigger>
<Icons.Plus /> <Button variant="primary">
</Icon> <Icon>
<Text>{formatMessage(labels.createTeam)}</Text> <Icons.Plus />
</Button> </Icon>
<Modal title={formatMessage(labels.createTeam)}> <Text>{formatMessage(labels.createTeam)}</Text>
{close => <TeamAddForm onSave={handleSave} onClose={close} />} </Button>
</Modal> <Modal title={formatMessage(labels.createTeam)}>
</ModalTrigger> {close => <TeamAddForm onSave={handleSave} onClose={close} />}
</Modal>
</ModalTrigger>
)}
</>
); );
return ( return (

View file

@ -35,6 +35,9 @@ export function UserAddForm({ onSave, onClose }) {
if (value === ROLES.admin) { if (value === ROLES.admin) {
return formatMessage(labels.admin); return formatMessage(labels.admin);
} }
if (value === ROLES.viewOnly) {
return formatMessage(labels.viewOnly);
}
}; };
return ( return (
@ -52,6 +55,7 @@ export function UserAddForm({ onSave, onClose }) {
<FormRow label={formatMessage(labels.role)}> <FormRow label={formatMessage(labels.role)}>
<FormInput name="role" rules={{ required: formatMessage(labels.required) }}> <FormInput name="role" rules={{ required: formatMessage(labels.required) }}>
<Dropdown renderValue={renderValue}> <Dropdown renderValue={renderValue}>
<Item key={ROLES.viewOnly}>{formatMessage(labels.viewOnly)}</Item>
<Item key={ROLES.user}>{formatMessage(labels.user)}</Item> <Item key={ROLES.user}>{formatMessage(labels.user)}</Item>
<Item key={ROLES.admin}>{formatMessage(labels.admin)}</Item> <Item key={ROLES.admin}>{formatMessage(labels.admin)}</Item>
</Dropdown> </Dropdown>

View file

@ -35,6 +35,9 @@ export function UserEditForm({ userId, data, onSave }) {
if (value === ROLES.admin) { if (value === ROLES.admin) {
return formatMessage(labels.admin); return formatMessage(labels.admin);
} }
if (value === ROLES.viewOnly) {
return formatMessage(labels.viewOnly);
}
}; };
return ( return (
@ -57,6 +60,7 @@ export function UserEditForm({ userId, data, onSave }) {
<FormRow label={formatMessage(labels.role)}> <FormRow label={formatMessage(labels.role)}>
<FormInput name="role" rules={{ required: formatMessage(labels.required) }}> <FormInput name="role" rules={{ required: formatMessage(labels.required) }}>
<Dropdown renderValue={renderValue}> <Dropdown renderValue={renderValue}>
<Item key={ROLES.viewOnly}>{formatMessage(labels.viewOnly)}</Item>
<Item key={ROLES.user}>{formatMessage(labels.user)}</Item> <Item key={ROLES.user}>{formatMessage(labels.user)}</Item>
<Item key={ROLES.admin}>{formatMessage(labels.admin)}</Item> <Item key={ROLES.admin}>{formatMessage(labels.admin)}</Item>
</Dropdown> </Dropdown>

View file

@ -7,6 +7,7 @@ import WebsitesTable from 'components/pages/settings/websites/WebsitesTable';
import useApi from 'hooks/useApi'; import useApi from 'hooks/useApi';
import useUser from 'hooks/useUser'; import useUser from 'hooks/useUser';
import useMessages from 'hooks/useMessages'; import useMessages from 'hooks/useMessages';
import { ROLES } from 'lib/constants';
export function WebsitesList() { export function WebsitesList() {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
@ -26,17 +27,21 @@ export function WebsitesList() {
}; };
const addButton = ( const addButton = (
<ModalTrigger> <>
<Button variant="primary"> {user.role !== ROLES.viewOnly && (
<Icon> <ModalTrigger>
<Icons.Plus /> <Button variant="primary">
</Icon> <Icon>
<Text>{formatMessage(labels.addWebsite)}</Text> <Icons.Plus />
</Button> </Icon>
<Modal title={formatMessage(labels.addWebsite)}> <Text>{formatMessage(labels.addWebsite)}</Text>
{close => <WebsiteAddForm onSave={handleSave} onClose={close} />} </Button>
</Modal> <Modal title={formatMessage(labels.addWebsite)}>
</ModalTrigger> {close => <WebsiteAddForm onSave={handleSave} onClose={close} />}
</Modal>
</ModalTrigger>
)}
</>
); );
return ( return (

View file

@ -1,4 +1,9 @@
-- edit event_data values
ALTER TABLE "event_data" RENAME COLUMN "event_date_value" TO "date_value"; ALTER TABLE "event_data" RENAME COLUMN "event_date_value" TO "date_value";
ALTER TABLE "event_data" RENAME COLUMN "event_numeric_value" TO "numeric_value"; ALTER TABLE "event_data" RENAME COLUMN "event_numeric_value" TO "number_value";
ALTER TABLE "event_data" RENAME COLUMN "event_string_value" TO "string_value"; ALTER TABLE "event_data" RENAME COLUMN "event_string_value" TO "string_value";
ALTER TABLE "event_data" RENAME COLUMN "event_data_type" TO "data_type"; ALTER TABLE "event_data" RENAME COLUMN "event_data_type" TO "data_type";
-- add job_id
ALTER TABLE "website_event" ADD COLUMN "job_id" UUID AFTER "created_at";
ALTER TABLE "event_data" ADD COLUMN "job_id" UUID AFTER "created_at";

View file

@ -1,2 +0,0 @@
ALTER TABLE "website_event" ADD COLUMN "job_id" UUID AFTER "created_at";
ALTER TABLE "event_data" ADD COLUMN "job_id" UUID AFTER "created_at";

View file

@ -119,7 +119,7 @@ CREATE TABLE umami.event_data
event_name String, event_name String,
event_key String, event_key String,
string_value Nullable(String), string_value Nullable(String),
numeric_value Nullable(Decimal64(4)), --922337203685477.5625 number_value Nullable(Decimal64(4)), --922337203685477.5625
date_value Nullable(DateTime('UTC')), date_value Nullable(DateTime('UTC')),
data_type UInt32, data_type UInt32,
created_at DateTime('UTC'), created_at DateTime('UTC'),
@ -137,7 +137,7 @@ CREATE TABLE umami.event_data_queue (
event_name String, event_name String,
event_key String, event_key String,
string_value Nullable(String), string_value Nullable(String),
numeric_value Nullable(Decimal64(4)), --922337203685477.5625 number_value Nullable(Decimal64(4)), --922337203685477.5625
date_value Nullable(DateTime('UTC')), date_value Nullable(DateTime('UTC')),
data_type UInt32, data_type UInt32,
created_at DateTime('UTC'), created_at DateTime('UTC'),
@ -161,7 +161,7 @@ SELECT website_id,
event_name, event_name,
event_key, event_key,
string_value, string_value,
numeric_value, number_value,
date_value, date_value,
data_type, data_type,
created_at created_at

View file

@ -15,7 +15,7 @@
ALTER TABLE `event_data` RENAME COLUMN `event_data_type` TO `data_type`; ALTER TABLE `event_data` RENAME COLUMN `event_data_type` TO `data_type`;
ALTER TABLE `event_data` RENAME COLUMN `event_date_value` TO `date_value`; ALTER TABLE `event_data` RENAME COLUMN `event_date_value` TO `date_value`;
ALTER TABLE `event_data` RENAME COLUMN `event_id` TO `event_data_id`; ALTER TABLE `event_data` RENAME COLUMN `event_id` TO `event_data_id`;
ALTER TABLE `event_data` RENAME COLUMN `event_numeric_value` TO `numeric_value`; ALTER TABLE `event_data` RENAME COLUMN `event_numeric_value` TO `number_value`;
ALTER TABLE `event_data` RENAME COLUMN `event_string_value` TO `string_value`; ALTER TABLE `event_data` RENAME COLUMN `event_string_value` TO `string_value`;
-- CreateTable -- CreateTable
@ -24,10 +24,10 @@ CREATE TABLE `session_data` (
`website_id` VARCHAR(36) NOT NULL, `website_id` VARCHAR(36) NOT NULL,
`session_id` VARCHAR(36) NOT NULL, `session_id` VARCHAR(36) NOT NULL,
`event_key` VARCHAR(500) NOT NULL, `event_key` VARCHAR(500) NOT NULL,
`event_string_value` VARCHAR(500) NULL, `string_value` VARCHAR(500) NULL,
`event_numeric_value` DECIMAL(19, 4) NULL, `number_value` DECIMAL(19, 4) NULL,
`event_date_value` TIMESTAMP(0) NULL, `date_value` TIMESTAMP(0) NULL,
`event_data_type` INTEGER UNSIGNED NOT NULL, `data_type` INTEGER UNSIGNED NOT NULL,
`created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0), `created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0),
INDEX `session_data_created_at_idx`(`created_at`), INDEX `session_data_created_at_idx`(`created_at`),

View file

@ -101,7 +101,7 @@ model EventData {
websiteId String @map("website_id") @db.VarChar(36) websiteId String @map("website_id") @db.VarChar(36)
eventKey String @map("event_key") @db.VarChar(500) eventKey String @map("event_key") @db.VarChar(500)
stringValue String? @map("string_value") @db.VarChar(500) stringValue String? @map("string_value") @db.VarChar(500)
numericValue Decimal? @map("numeric_value") @db.Decimal(19, 4) numberValue Decimal? @map("number_value") @db.Decimal(19, 4)
dateValue DateTime? @map("date_value") @db.Timestamp(0) dateValue DateTime? @map("date_value") @db.Timestamp(0)
dataType Int @map("data_type") @db.UnsignedInt dataType Int @map("data_type") @db.UnsignedInt
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0)
@ -117,15 +117,15 @@ model EventData {
} }
model SessionData { model SessionData {
id String @id() @map("session_data_id") @db.VarChar(36) id String @id() @map("session_data_id") @db.VarChar(36)
websiteId String @map("website_id") @db.VarChar(36) websiteId String @map("website_id") @db.VarChar(36)
sessionId String @map("session_id") @db.VarChar(36) sessionId String @map("session_id") @db.VarChar(36)
eventKey String @map("event_key") @db.VarChar(500) eventKey String @map("event_key") @db.VarChar(500)
eventStringValue String? @map("event_string_value") @db.VarChar(500) stringValue String? @map("string_value") @db.VarChar(500)
eventNumericValue Decimal? @map("event_numeric_value") @db.Decimal(19, 4) numberValue Decimal? @map("number_value") @db.Decimal(19, 4)
eventDateValue DateTime? @map("event_date_value") @db.Timestamp(0) dateValue DateTime? @map("date_value") @db.Timestamp(0)
eventDataType Int @map("event_data_type") @db.UnsignedInt dataType Int @map("data_type") @db.UnsignedInt
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamp(0)
website Website @relation(fields: [websiteId], references: [id]) website Website @relation(fields: [websiteId], references: [id])
session Session @relation(fields: [sessionId], references: [id]) session Session @relation(fields: [sessionId], references: [id])

View file

@ -2,7 +2,7 @@
ALTER TABLE "event_data" RENAME COLUMN "event_data_type" TO "data_type"; ALTER TABLE "event_data" RENAME COLUMN "event_data_type" TO "data_type";
ALTER TABLE "event_data" RENAME COLUMN "event_date_value" TO "date_value"; ALTER TABLE "event_data" RENAME COLUMN "event_date_value" TO "date_value";
ALTER TABLE "event_data" RENAME COLUMN "event_id" TO "event_data_id"; ALTER TABLE "event_data" RENAME COLUMN "event_id" TO "event_data_id";
ALTER TABLE "event_data" RENAME COLUMN "event_numeric_value" TO "numeric_value"; ALTER TABLE "event_data" RENAME COLUMN "event_numeric_value" TO "number_value";
ALTER TABLE "event_data" RENAME COLUMN "event_string_value" TO "string_value"; ALTER TABLE "event_data" RENAME COLUMN "event_string_value" TO "string_value";
-- CreateTable -- CreateTable
@ -12,7 +12,7 @@ CREATE TABLE "session_data" (
"session_id" UUID NOT NULL, "session_id" UUID NOT NULL,
"session_key" VARCHAR(500) NOT NULL, "session_key" VARCHAR(500) NOT NULL,
"string_value" VARCHAR(500), "string_value" VARCHAR(500),
"numeric_value" DECIMAL(19,4), "number_value" DECIMAL(19,4),
"date_value" TIMESTAMPTZ(6), "date_value" TIMESTAMPTZ(6),
"data_type" INTEGER NOT NULL, "data_type" INTEGER NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP, "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

View file

@ -101,7 +101,7 @@ model EventData {
websiteEventId String @map("website_event_id") @db.Uuid websiteEventId String @map("website_event_id") @db.Uuid
eventKey String @map("event_key") @db.VarChar(500) eventKey String @map("event_key") @db.VarChar(500)
stringValue String? @map("string_value") @db.VarChar(500) stringValue String? @map("string_value") @db.VarChar(500)
numericValue Decimal? @map("numeric_value") @db.Decimal(19, 4) numberValue Decimal? @map("number_value") @db.Decimal(19, 4)
dateValue DateTime? @map("date_value") @db.Timestamptz(6) dateValue DateTime? @map("date_value") @db.Timestamptz(6)
dataType Int @map("data_type") @db.Integer dataType Int @map("data_type") @db.Integer
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
@ -116,16 +116,16 @@ model EventData {
} }
model SessionData { model SessionData {
id String @id() @map("session_data_id") @db.Uuid id String @id() @map("session_data_id") @db.Uuid
websiteId String @map("website_id") @db.Uuid websiteId String @map("website_id") @db.Uuid
sessionId String @map("session_id") @db.Uuid sessionId String @map("session_id") @db.Uuid
sessionKey String @map("session_key") @db.VarChar(500) sessionKey String @map("session_key") @db.VarChar(500)
stringValue String? @map("string_value") @db.VarChar(500) stringValue String? @map("string_value") @db.VarChar(500)
numericValue Decimal? @map("numeric_value") @db.Decimal(19, 4) numberValue Decimal? @map("number_value") @db.Decimal(19, 4)
dateValue DateTime? @map("date_value") @db.Timestamptz(6) dateValue DateTime? @map("date_value") @db.Timestamptz(6)
dataType Int @map("data_type") @db.Integer dataType Int @map("data_type") @db.Integer
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
deletedAt DateTime? @default(now()) @map("deleted_at") @db.Timestamptz(6) deletedAt DateTime? @default(now()) @map("deleted_at") @db.Timestamptz(6)
website Website @relation(fields: [websiteId], references: [id]) website Website @relation(fields: [websiteId], references: [id])
session Session @relation(fields: [sessionId], references: [id]) session Session @relation(fields: [sessionId], references: [id])

View file

@ -82,17 +82,17 @@ function getEventDataFilterQuery(
switch (type) { switch (type) {
case 'number': case 'number':
ac.push(`and event_numeric_value = {eventValue${i}:UInt64})`); ac.push(`and number_value = {eventValue${i}:UInt64})`);
break; break;
case 'string': case 'string':
ac.push(`and event_string_value = {eventValue${i}:String})`); ac.push(`and string_value = {eventValue${i}:String})`);
break; break;
case 'boolean': case 'boolean':
ac.push(`and event_string_value = {eventValue${i}:String})`); ac.push(`and string_value = {eventValue${i}:String})`);
value = cv ? 'true' : 'false'; value = cv ? 'true' : 'false';
break; break;
case 'date': case 'date':
ac.push(`and event_date_value = {eventValue${i}:DateTime('UTC')})`); ac.push(`and date_value = {eventValue${i}:DateTime('UTC')})`);
break; break;
} }

View file

@ -92,6 +92,7 @@ export const KAFKA_TOPIC = {
export const ROLES = { export const ROLES = {
admin: 'admin', admin: 'admin',
user: 'user', user: 'user',
viewOnly: 'view-only',
teamOwner: 'team-owner', teamOwner: 'team-owner',
teamMember: 'team-member', teamMember: 'team-member',
} as const; } as const;
@ -114,6 +115,7 @@ export const ROLE_PERMISSIONS = {
PERMISSIONS.websiteDelete, PERMISSIONS.websiteDelete,
PERMISSIONS.teamCreate, PERMISSIONS.teamCreate,
], ],
[ROLES.viewOnly]: [],
[ROLES.teamOwner]: [PERMISSIONS.teamUpdate, PERMISSIONS.teamDelete], [ROLES.teamOwner]: [PERMISSIONS.teamUpdate, PERMISSIONS.teamDelete],
[ROLES.teamMember]: [], [ROLES.teamMember]: [],
} as const; } as const;

View file

@ -94,20 +94,20 @@ function getEventDataFilterQuery(
switch (type) { switch (type) {
case 'number': case 'number':
ac.push(`and event_numeric_value = $${params.length + 1})`); ac.push(`and number_value = $${params.length + 1})`);
params.push(value); params.push(value);
break; break;
case 'string': case 'string':
ac.push(`and event_string_value = $${params.length + 1})`); ac.push(`and string_value = $${params.length + 1})`);
params.push(decodeURIComponent(cv.eventValue as string)); params.push(decodeURIComponent(cv.eventValue as string));
break; break;
case 'boolean': case 'boolean':
ac.push(`and event_string_value = $${params.length + 1})`); ac.push(`and string_value = $${params.length + 1})`);
params.push(decodeURIComponent(cv.eventValue as string)); params.push(decodeURIComponent(cv.eventValue as string));
value = cv ? 'true' : 'false'; value = cv ? 'true' : 'false';
break; break;
case 'date': case 'date':
ac.push(`and event_date_value = $${params.length + 1})`); ac.push(`and date_value = $${params.length + 1})`);
params.push(cv.eventValue); params.push(cv.eventValue);
break; break;
} }

View file

@ -81,7 +81,7 @@ async function clickhouseQuery(data: {
a.dynamicDataType === DATA_TYPE.array a.dynamicDataType === DATA_TYPE.array
? a.value ? a.value
: null, : null,
numeric_value: a.dynamicDataType === DATA_TYPE.number ? a.value : null, number_value: a.dynamicDataType === DATA_TYPE.number ? a.value : null,
date_value: a.dynamicDataType === DATA_TYPE.date ? getDateFormat(a.value) : null, date_value: a.dynamicDataType === DATA_TYPE.date ? getDateFormat(a.value) : null,
data_type: a.dynamicDataType, data_type: a.dynamicDataType,
created_at: createdAt, created_at: createdAt,