Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send operation logs and display them for keyboard designers #789

Merged
merged 5 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ service cloud.firestore {
&& (request.auth.uid == resource.data.uid);
}

match /logs/v1/operations/{operationLogID} {
allow create;
allow update: if false;
allow delete: if false;
allow read: if false;
}

function isAuthenticated() {
return request.auth.uid != null;
}
Expand All @@ -149,4 +156,4 @@ service cloud.firestore {
return get(/databases/$(database)/documents/keyboards/v2/definitions/$(definitionID));
}
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-draggable": "^4.4.3",
"react-google-charts": "^4.0.1",
"react-helmet-async": "^1.0.9",
"react-image-gallery": "^1.2.7",
"react-redux": "^7.2.2",
Expand Down
20 changes: 17 additions & 3 deletions src/actions/hid.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { sendEventToGoogleAnalytics } from '../utils/GoogleAnalytics';
import { LayoutOption } from '../components/configure/keymap/Keymap';
import { maxValueByBitLength } from '../utils/NumberUtils';
import { KeyOp } from '../gen/types/KeyboardDefinition';
import { getEncoderIdList } from './utils';
import { getEncoderIdList, sendOperationLog } from './utils';
import { bmpKeyInfoList } from '../services/hid/KeycodeInfoListBmp';

const PRODUCT_PREFIX_FOR_BLE_MICRO_PRO = '(BMP)';
Expand Down Expand Up @@ -278,7 +278,7 @@ export const hidActionsThunk = {
dispatch: ThunkDispatch<RootState, undefined, ActionTypes>,
getState: () => RootState
) => {
const { app, entities } = getState();
const { app, entities, storage, auth } = getState();
const keyboard = entities.keyboard!;
const result = await keyboard.open();
if (!result.success) {
Expand All @@ -291,6 +291,13 @@ export const hidActionsThunk = {
product_id: keyboard.getInformation().productId,
product_name: keyboard.getInformation().productName,
});
await sendOperationLog(
auth.instance!,
storage.instance!,
app.localAuthenticationInfo.uid,
entities.keyboardDefinitionDocument!.id,
'configure/open'
);

const isBleMicroPro = keyboard
.getInformation()
Expand Down Expand Up @@ -487,13 +494,20 @@ export const hidActionsThunk = {
dispatch: ThunkDispatch<RootState, undefined, ActionTypes>,
getState: () => RootState
) => {
const { app, entities } = getState();
const { app, entities, storage, auth } = getState();
const keyboard: IKeyboard = entities.keyboard!;
sendEventToGoogleAnalytics('configure/flash', {
vendor_id: keyboard.getInformation().vendorId,
product_id: keyboard.getInformation().productId,
product_name: keyboard.getInformation().productName,
});
await sendOperationLog(
auth.instance!,
storage.instance!,
app.localAuthenticationInfo.uid,
entities.keyboardDefinitionDocument!.id,
'configure/flash'
);
const remaps = app.remaps;
for (let layer = 0; layer < remaps.length; layer++) {
const remap = remaps[layer];
Expand Down
8 changes: 8 additions & 0 deletions src/actions/keyboards.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
IBuildableFirmwareFileType,
IKeyboardDefinitionAuthorType,
IKeyboardDefinitionDocument,
IKeyboardStatistics,
IStore,
} from '../services/storage/Storage';
import { ThunkAction, ThunkDispatch } from 'redux-thunk';
Expand Down Expand Up @@ -196,6 +197,7 @@ export const KEYBOARDS_EDIT_DEFINITION_UPDATE_ORGANIZATION_ID = `${KEYBOARDS_EDI
export const KEYBOARDS_EDIT_DEFINITION_UPDATE_AUTHOR_TYPE = `${KEYBOARDS_EDIT_DEFINITION_ACTIONS}/UpdateAuthorType`;
export const KEYBOARDS_EDIT_DEFINITION_UPDATE_BUILDABLE_FIRMWARE_FILE = `${KEYBOARDS_EDIT_DEFINITION_ACTIONS}/UpdateBuildableFirmwareFile`;
export const KEYBOARDS_EDIT_DEFINITION_UPDATE_BUILDABLE_FIRMWARE_CODE_PARAMETERS = `${KEYBOARDS_EDIT_DEFINITION_ACTIONS}/UpdateBuildableFirmwareCodeParameters`;
export const KEYBOARDS_EDIT_DEFINITION_UPDATE_KEYBOARD_STATISTICS = `${KEYBOARDS_EDIT_DEFINITION_ACTIONS}/UpdateKeyboardStatistics`;

export const KeyboardsEditDefinitionActions = {
clear: () => {
Expand Down Expand Up @@ -447,6 +449,12 @@ export const KeyboardsEditDefinitionActions = {
value: parameters,
};
},
updateKeyboardStatistics: (statistics: IKeyboardStatistics | undefined) => {
return {
type: KEYBOARDS_EDIT_DEFINITION_UPDATE_KEYBOARD_STATISTICS,
value: statistics,
};
},
};

type ActionTypes = ReturnType<
Expand Down
21 changes: 19 additions & 2 deletions src/actions/storage.action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,23 @@ export const storageActionsThunk = {
);
return;
}
const fetchKeyboardStatisticsResult =
await storage.instance!.fetchKeyboardStatistics(definitionId);
if (isError(fetchKeyboardStatisticsResult)) {
console.error(fetchKeyboardStatisticsResult.cause);
dispatch(
NotificationActions.addError(
fetchKeyboardStatisticsResult.error,
fetchKeyboardStatisticsResult.cause
)
);
return;
}
dispatch(
KeyboardsEditDefinitionActions.updateKeyboardStatistics(
fetchKeyboardStatisticsResult.value
)
);
dispatch(
StorageActions.updateBuildableFirmware(
fetchBuildableFirmwareResult.value
Expand Down Expand Up @@ -601,7 +618,7 @@ export const storageActionsThunk = {
) => {
const { storage, auth, keyboards, github } = getState();
const keyboardDefinition = keyboards.createdefinition.keyboardDefinition!;
const user = auth.instance!.getCurrentAuthenticatedUser();
const user = auth.instance!.getCurrentAuthenticatedUserIgnoreNull();
const githubProviderDataResult = getGitHubProviderData(user);
if (!githubProviderDataResult.exists) {
console.error('The user does not have a GitHub Provider data.');
Expand Down Expand Up @@ -673,7 +690,7 @@ export const storageActionsThunk = {
const { storage, auth, keyboards, github } = getState();
const keyboardDefinition = keyboards.createdefinition.keyboardDefinition!;

const user = auth.instance!.getCurrentAuthenticatedUser();
const user = auth.instance!.getCurrentAuthenticatedUserIgnoreNull();
const githubProviderDataResutl = getGitHubProviderData(user);
if (!githubProviderDataResutl.exists) {
console.error('The user does not have a GitHub Provider data.');
Expand Down
19 changes: 19 additions & 0 deletions src/actions/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { KeyOp } from '../gen/types/KeyboardDefinition';
import KeyboardModel from '../models/KeyboardModel';
import { IAuth } from '../services/auth/Auth';
import { IOperationLogType, IStorage } from '../services/storage/Storage';

export const getEncoderIdList = (
keymapDefinition: ((string | KeyOp)[] | { name: string })[]
Expand All @@ -13,3 +15,20 @@ export const getEncoderIdList = (
return result;
}, []);
};

export const sendOperationLog = async (
auth: IAuth,
storage: IStorage,
localAuthenticationUid: string,
keyboardDefinitionId: string,
operation: IOperationLogType
): Promise<void> => {
let uid: string;
const user = auth.getCurrentAuthenticatedUserOrNull();
if (user === null) {
uid = `local:${localAuthenticationUid}`;
} else {
uid = `firebase:${user.uid}`;
}
await storage.sendOperationLog(uid, keyboardDefinitionId, operation);
};
6 changes: 3 additions & 3 deletions src/components/common/auth/ProfileIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default class ProfileIcon extends React.Component<
}

renderLinkGoogleAccountMenu() {
const user = this.props.auth!.getCurrentAuthenticatedUser();
const user = this.props.auth!.getCurrentAuthenticatedUserIgnoreNull();
if (user && !getGoogleProviderData(user).exists) {
return (
<MenuItem
Expand All @@ -89,7 +89,7 @@ export default class ProfileIcon extends React.Component<
}

renderLinkGitHubAccountMenu() {
const user = this.props.auth!.getCurrentAuthenticatedUser();
const user = this.props.auth!.getCurrentAuthenticatedUserIgnoreNull();
if (user && !getGitHubProviderData(user).exists) {
return (
<MenuItem
Expand All @@ -107,7 +107,7 @@ export default class ProfileIcon extends React.Component<
render() {
const { authMenuAnchorEl } = this.state;
if (this.props.signedIn) {
const user = this.props.auth!.getCurrentAuthenticatedUser();
const user = this.props.auth!.getCurrentAuthenticatedUserIgnoreNull();
const profileImageUrl = user.photoURL || '';
const profileDisplayName = user.displayName || '';
let avatar: React.ReactNode;
Expand Down
2 changes: 1 addition & 1 deletion src/components/configure/info/InfoDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export default class InfoDialog extends React.Component<
googleFormUrl={this.googleFormUrl}
authenticatedUser={
this.props.auth
? this.props.auth.getCurrentAuthenticatedUser()
? this.props.auth.getCurrentAuthenticatedUserIgnoreNull()
: undefined
}
organization={this.props.organization}
Expand Down
6 changes: 4 additions & 2 deletions src/components/configure/keymaplist/KeymapListPopover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export default class KeymapListPopover extends React.Component<
labelLang
);

const uid = this.props.auth!.getCurrentAuthenticatedUser().uid;
const uid = this.props.auth!.getCurrentAuthenticatedUserIgnoreNull().uid;
if (uid !== savedKeymapData.author_uid) {
this.props.createOrUpdateAppliedKeymap!(savedKeymapData);
}
Expand Down Expand Up @@ -284,7 +284,9 @@ export default class KeymapListPopover extends React.Component<
<KeymapSaveDialog
open={this.state.openKeymapSaveDialog}
savedKeymapData={this.state.savedKeymapData}
authorUid={this.props.auth!.getCurrentAuthenticatedUser().uid}
authorUid={
this.props.auth!.getCurrentAuthenticatedUserIgnoreNull().uid
}
authorDisplayName={this.props.auth!.getCurrentAuthenticatedUserDisplayName()}
onClose={() => {
this.onCloseKeymapSaveDialog();
Expand Down
1 change: 1 addition & 0 deletions src/components/keyboards/content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function Contents(props: ContentsProps) {
case KeyboardsPhase.catalog:
case KeyboardsPhase.firmware:
case KeyboardsPhase.build:
case KeyboardsPhase.statistics:
return <EditKeyboard />;
default:
throw new Error(
Expand Down
9 changes: 8 additions & 1 deletion src/components/keyboards/editdefinition/EditDefinition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import DefinitionForm from './definitionform/DefinitionForm';
import CatalogForm from './catalogform/CatalogForm.container';
import FirmwareForm from './firmwareform/FirmwareForm.container';
import BuildForm from './buildform/BuildForm.container';
import Statistics from './statistics/Statistics.container';

type ConfirmDialogMode =
| 'save_as_draft'
Expand Down Expand Up @@ -207,6 +208,8 @@ export default function EditDefinition(props: EditKeyboardProps) {
props.updatePhase!('firmware');
} else if (tabIndex === 3) {
props.updatePhase!('build');
} else if (tabIndex === 4) {
props.updatePhase!('statistics');
} else {
throw new Error(`Invalid tabIndex: ${tabIndex}`);
}
Expand Down Expand Up @@ -280,7 +283,9 @@ export default function EditDefinition(props: EditKeyboardProps) {
? 1
: props.phase === 'firmware'
? 2
: 3
: props.phase === 'build'
? 3
: 4
}
indicatorColor="primary"
textColor="primary"
Expand All @@ -292,6 +297,7 @@ export default function EditDefinition(props: EditKeyboardProps) {
<Tab label="Catalog" />
<Tab label="Firmware" />
<Tab label="Build" />
<Tab label="Statistics" />
</Tabs>
</div>
) : null}
Expand Down Expand Up @@ -361,6 +367,7 @@ export default function EditDefinition(props: EditKeyboardProps) {
{props.phase === 'catalog' ? <CatalogForm /> : null}
{props.phase === 'firmware' ? <FirmwareForm /> : null}
{props.phase === 'build' ? <BuildForm /> : null}
{props.phase === 'statistics' ? <Statistics /> : null}
</CardContent>
</Card>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { RootState } from '../../../../store/state';
import { connect } from 'react-redux';
import Statistics from './Statistics';

const mapStateToProps = (state: RootState) => {
return {
statistics: state.keyboards.editdefinition.keyboardStatistics,
};
};
export type StatisticsStateType = ReturnType<typeof mapStateToProps>;

// eslint-disable-next-line no-unused-vars
const mapDispatchToProps = (_dispatch: any) => {
return {};
};
export type StatisticsActionsType = ReturnType<typeof mapDispatchToProps>;

export default connect(mapStateToProps, mapDispatchToProps)(Statistics);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import 'src/variables';

.edit-definition-statistics {
&-container {
display: flex;
flex-direction: column;
width: 100%;
}
}
Loading
Loading