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

Feat/time series value chart #87

Merged
merged 32 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bba2fe8
docs: Fixed get started link in README.md
buddh4 Jul 29, 2024
233dcf1
feat(analytics): Implemented time-series chart type
buddh4 Aug 12, 2024
2f586f8
feat: ContentPicker implementation
buddh4 Aug 15, 2024
75f5c69
feat(web): Improved content picker api
buddh4 Sep 8, 2024
272c88c
fix(web): Remove dummy oauth provider in login view
buddh4 Sep 9, 2024
849d48a
fix(web): Use of invalid registration path in mail invitation
buddh4 Sep 10, 2024
8d198ea
fix(web): Added missing invitation routes to module
buddh4 Sep 10, 2024
0291521
fix(web): Set isPublic to mail invitation
buddh4 Sep 10, 2024
72fef0a
fix(api): Registration mode not set properly in app config
buddh4 Sep 10, 2024
12ee5ca
fix: Use of wrong doc url
buddh4 Sep 10, 2024
74f263a
fix(web): Fixed help tour style in dark mode
buddh4 Sep 10, 2024
c84b5ec
fix(web): HelpTour only starts once
buddh4 Sep 10, 2024
d02d3e0
fix(web): Consider registration mode for invitations
buddh4 Sep 10, 2024
43473ad
style(web): Fixed role badge text style in dark mode
buddh4 Sep 10, 2024
ca7eb2e
fix(api): Fix partial update with getDefaults not working
buddh4 Sep 10, 2024
524b690
usability(habits): Use of default score 1
buddh4 Sep 10, 2024
cb02d8a
usability(habits): Loosen restrictions on min/max input rules
buddh4 Sep 10, 2024
9c821fb
usability(tasks): Always use per-user timer in tasks
buddh4 Sep 10, 2024
15160f0
fix(web): ContentDropdown update model not reactive
buddh4 Sep 10, 2024
a98bf34
fix(web): Removed test content picker
buddh4 Sep 10, 2024
23c1d40
fix(web): Slight alignment of number data point config rules
buddh4 Sep 10, 2024
34f06a6
fix(time-series): Can not overwrite datapoint after type change
buddh4 Sep 10, 2024
c40d184
feat: Finished implementation of journal and habits value charts
buddh4 Sep 10, 2024
73af943
fix(web): Fixed menu issue with acitivty feature without active activ…
buddh4 Sep 10, 2024
53b5765
fix(web): Milestone relations are not visible
buddh4 Sep 10, 2024
c55e618
fix(ui): Replaced trim on change with trim on blur
buddh4 Sep 10, 2024
62de17e
test: Fixed test issues
buddh4 Sep 10, 2024
2f55c5d
fix(time-series): Type issue in TimeSeriesContentModel
buddh4 Sep 10, 2024
9d70eb8
test: Fixed failing tests
buddh4 Sep 10, 2024
5bad20e
chore: Fixed lint errors
buddh4 Sep 10, 2024
52e0945
fix(api): Fetch of Notifications does not work
buddh4 Sep 10, 2024
b64871a
fix: User invitation texts and live issue
buddh4 Sep 10, 2024
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ platforms.

## Getting Started

To get started with Lyvely, follow the installation instructions in our [documentation](https://docs.lyvely.app).
To get started with Lyvely, follow the installation instructions in our [documentation](https://www.lyvelyjs.com/docs/admin/intro/installation).

## Core Features

Expand Down
4 changes: 2 additions & 2 deletions common/config/rush/browser-approved-packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@
},
{
"name": "@lyvely/analytics-interface",
"allowedCategories": [ "feature" ]
"allowedCategories": [ "feature", "lib" ]
},
{
"name": "@lyvely/analytics-web",
"allowedCategories": [ "application", "feature" ]
"allowedCategories": [ "application", "feature", "lib" ]
},
{
"name": "@lyvely/calendar-plan-interface",
Expand Down
2 changes: 1 addition & 1 deletion common/config/rush/nonbrowser-approved-packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"packages": [
{
"name": "@lyvely/analytics",
"allowedCategories": [ "application", "feature" ]
"allowedCategories": [ "application", "feature", "lib" ]
},
{
"name": "@lyvely/api",
Expand Down
35 changes: 31 additions & 4 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docker/.env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ SSL_CERT_DOCS=lyvely.docs.crt
SSL_CERT_KEY_DOCS=lyvely.docs.key
MAX_BODY_SIZE=10m
NODE_ENV=production
DOCS_URL=https://docs.lyvely.app
DOCS_URL=https://lyvelyjs.com
MONGODB_USER=957
REDIS_USER=959
NGINX_USER=958
Expand Down
16 changes: 6 additions & 10 deletions packages/applications/docs/docs/dev/framework/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,6 @@ within our interface package.
```typescript title=polls/packages/interface/src/models/create-poll.model.ts
@Exclude()
export class CreatePollModel extends CreateContentModel<CreatePollModel> {
@Expose()
@IsString()
@MaxLength(200)
title: string;

@Expose()
@IsString()
@MaxLength(10_000)
text: string;

@Expose()
@IsDate()
expiresAt: Date;
Expand All @@ -54,10 +44,16 @@ export class CreatePollModel extends CreateContentModel<CreatePollModel> {

The `CreateContentModel` class comes with default support for the following fields:

- `title`: A required content title.
- `text`: An optional content text like a description.
- `tagNames`: Allows attaching tag names to a content instance.
- `parentId`: Used to specify the parent ID of a content instance. This field is typically populated by default when
creating a content instance within a content-details discussion.

:::tip
In the rare case your content does not support `title` and `text` use the `CreateBaseContentModel` instead.
:::

### Update Content Model

When handling updates, it's often preferred to allow partial updates. This approach enables us to modify
Expand Down
2 changes: 1 addition & 1 deletion packages/applications/docs/docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const darkTheme = themes.dracula;
const config: Config = {
title: 'Lyvely Documentation',
tagline: 'What else...',
url: 'https://docs.lyvely.app',
url: 'https://lyvelyjs.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ServerConfiguration } from "@lyvely/api";
export default {
appName: "lyvely.app",
operationMode: "standalone",
docUrl: "https://docs.lyvely.app",
docUrl: "https://lyvelyjs.com",
contactMail: "[email protected]",
redis: {
host: "localhost",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ServerConfiguration } from "@lyvely/api";
export default {
appName: "lyvely.app",
operationMode: "standalone",
docUrl: "https://docs.lyvely.app",
docUrl: "https://lyvelyjs.com",
contactMail: "[email protected]",
redis: {
host: "localhost",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class AppConfigService {
getAppConfig(req: OptionalUserRequest): IAppConfig<any> {
const config: IAppConfig<any> = {
appName: this.configService.get('appName', 'lyvely'),
docUrl: this.configService.get('docUrl', 'https://docs.lyvely.app'),
docUrl: this.configService.get('docUrl', 'https://lyvelyjs.com'),
modules: {},
};

Expand Down
6 changes: 5 additions & 1 deletion packages/core/api/src/config/lyvely-config.loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ export const loadConfigs = (
);

return Promise.all(configPromises)
.then((configs) => configs.reduce((acc, config) => merge(acc, config), {}))
.then((configs) =>
configs.reduce((acc, config) => {
return merge(acc, config);
}, {})
)
.then((mergedConfig) =>
withDbConfig
? loadDbConfig(mergedConfig).then((dbConfig) => ({ dbConfig, mergedConfig }))
Expand Down
2 changes: 1 addition & 1 deletion packages/core/api/src/config/lyvely.default.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const mail = process.env.MAIL_HOST
export default {
appName: process.env.APP_NAME || 'lyvely.app',
operationMode: 'standalone',
docUrl: 'https://docs.lyvely.app',
docUrl: 'https://lyvelyjs.com',
contactMail: '[email protected]',
modules: {
permissions: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { VisitorMode } from '@lyvely/interface';
export default {
appName: 'lyvely.app',
operationMode: 'standalone',
docUrl: 'https://docs.lyvely.app',
docUrl: 'https://lyvelyjs.com',
contactMail: '[email protected]',
redis: {
host: 'localhost',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Type, PropertiesOf, createBaseModelAndInit } from '@lyvely/common';
import {
ContentTypeEndpoint,
ContentModel,
CreateContentModel,
CreateBaseContentModel,
ContentUpdateResponse,
FieldValidationException,
TagModel,
Expand All @@ -20,7 +20,7 @@ import { ValidBody } from '@/core';

export abstract class AbstractContentTypeController<
TContent extends Content,
TCreateModel extends CreateContentModel,
TCreateModel extends CreateBaseContentModel,
TUpdateModel extends Partial<TCreateModel> = Partial<TCreateModel>,
TModel extends ContentModel<any> = ReturnType<TContent['toModel']>,
> implements ContentTypeEndpoint<TModel, TCreateModel, TUpdateModel>
Expand Down Expand Up @@ -70,7 +70,10 @@ export abstract class AbstractContentTypeController<
}

private transformUpdateModel(raw: PropertiesOf<TUpdateModel>): TUpdateModel {
return createBaseModelAndInit(this.updateModelType, raw);
return createBaseModelAndInit(this.updateModelType, raw, {
skipGetDefaults: true,
skipAfterInit: true,
});
}

protected async createUpdateResponse(
Expand Down
57 changes: 55 additions & 2 deletions packages/core/api/src/content/controllers/content.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,65 @@ import {
SetMilestoneModel,
ContentEndpoints,
UpdateTaskListItemModel,
ContentSearchResult,
ContentInfoResultModel,
} from '@lyvely/interface';
import { Post, HttpCode, HttpStatus, Param, Request, Put } from '@nestjs/common';
import { Post, HttpCode, HttpStatus, Param, Request, Put, Get, Query } from '@nestjs/common';
import { Policies } from '@/policies';
import { ContentService } from '../services';
import { ContentDeletePolicy, ContentWritePolicy } from '../policies';
import { ProtectedProfileContentRequest } from '../types';
import { ContentTypeController } from '../decorators';
import { ValidBody } from '@/core';
import { ProfileContext, type ProfileRequest } from '@/profiles';
import type { IContentInfoResult, IContentSearchQuery } from '@lyvely/interface';

@ContentTypeController(API_CONTENT)
export class ContentController implements ContentEndpoint {
constructor(private contentService: ContentService) {}

@Get(ContentEndpoints.SEARCH)
async search(
@Query() filter: IContentSearchQuery,
@Request() req: ProfileRequest
): Promise<ContentSearchResult> {
const { context } = req;
const content = await this.findContent(filter, req.context);
return new ContentSearchResult({ result: content.map((c) => c.toModel(context.user)) });
}

@Get(ContentEndpoints.INFOS)
async getInfos(
@Query() filter: IContentSearchQuery,
@Request() req: ProfileRequest
): Promise<IContentInfoResult> {
const contents = await this.findContent(filter, req.context);
const infos = contents.map((content) => content.getInfo());
return new ContentInfoResultModel({ infos });
}

/**
* Searches for content based on the provided filter and context.
*
* @param {IContentSearchQuery} filter - The criteria used to filter the search results.
* @param {ProfileContext} context - The context of the current user profile.
* @return {Promise<Object>} A promise that resolves to the search results.
*/
private async findContent(filter: IContentSearchQuery, context: ProfileContext) {
const tagIds = filter.tagId ? [filter.tagId] : [];
if (filter.tagIds?.length) {
tagIds.push(...filter.tagIds);
}
return this.contentService.search(context, {
cids: (filter.cids?.length || 0) > 1 ? filter.cids : undefined,
cid: filter.cids?.length === 1 ? filter.cids[0] : undefined,
tagIds: tagIds,
archived: filter.archived,
query: filter.query,
type: filter.type,
});
}

@Post(ContentEndpoints.ARCHIVE(':cid'))
@HttpCode(HttpStatus.NO_CONTENT)
@Policies(ContentDeletePolicy)
Expand Down Expand Up @@ -45,6 +91,14 @@ export class ContentController implements ContentEndpoint {
await this.contentService.setMilestone(context, model.mid);
}

@Post(ContentEndpoints.UNSET_MILESTONE(':cid'))
@HttpCode(HttpStatus.NO_CONTENT)
@Policies(ContentWritePolicy)
async unsetMilestone(@Param('cid') cid: string, @Request() req: ProtectedProfileContentRequest) {
const { context } = req;
await this.contentService.unsetMilestone(context);
}

@Put(ContentEndpoints.UPDATE_TASK_LIST_ITEM(':cid'))
@Policies(ContentWritePolicy)
async updateTaskListItem(
Expand All @@ -54,7 +108,6 @@ export class ContentController implements ContentEndpoint {
) {
const { context } = req;
await this.contentService.updateTaskListItem(context, model);
//await this.contentService.setMilestone(context, model.mid);
return context.content.toModel(context.user);
}
}
Loading
Loading