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

Update to standalone components #1174

Merged
merged 36 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e062a16
refactor(projects/_base): update to standalone components
jackofdiamond5 Nov 17, 2023
f34ea27
refactor(projects/_base_with_home): update to standalone components
jackofdiamond5 Nov 17, 2023
8793a3a
refactor(projects/empty): update to standalone components
jackofdiamond5 Nov 17, 2023
8731699
refactor(projects/_base): animations & gestures for standalone compon…
jackofdiamond5 Nov 20, 2023
45cbc76
refactor(*): separate dirs for standalone and module based projects
jackofdiamond5 Nov 21, 2023
de8223e
refactor(lint): update config
jackofdiamond5 Nov 21, 2023
c7158b7
refactor(templates): update imports
jackofdiamond5 Nov 21, 2023
452e3b2
refactor(_base/index): fix an import's path
jackofdiamond5 Nov 21, 2023
527cb42
refactor(IgxProjectLibrary): update rootPath dir
jackofdiamond5 Nov 22, 2023
8c80e6d
refactor(projects/side-nav): update to standalone components
jackofdiamond5 Nov 23, 2023
0b33b3c
refactor(projects/side-nav-auth): update to standalone components
jackofdiamond5 Nov 24, 2023
4331086
refactor(projects/_base): remove routing module
jackofdiamond5 Nov 24, 2023
eafe518
refactor(igx-ts): update templates to standalone
jackofdiamond5 Nov 28, 2023
cfea3b5
refactor(projects): add legacy projects on the same level as standalone
jackofdiamond5 Nov 28, 2023
86f5495
refactor(projects): export both legacy & standalone projects
jackofdiamond5 Nov 28, 2023
abb30f5
refactor(projects): update packages, do not register standalones
jackofdiamond5 Nov 29, 2023
71cc56b
refactor(projects): move main; update pkg.json
jackofdiamond5 Nov 29, 2023
0c49550
refactor(projects): update routing for standalone apps; rearrange con…
jackofdiamond5 Nov 30, 2023
911d3fa
chore(projects): fix indentation
jackofdiamond5 Nov 30, 2023
725022e
chore(projects): bump karma reporter version
jackofdiamond5 Dec 1, 2023
55f0baa
chore(projects): fix lint
jackofdiamond5 Dec 1, 2023
ab23fbf
chore(projects): use latin letters
jackofdiamond5 Dec 1, 2023
2c595df
refactor(projects-legacy): update project type
jackofdiamond5 Dec 4, 2023
d4aa5c6
refactor(projects): update templates; prettify code
jackofdiamond5 Dec 4, 2023
0de2228
refactor(projects): add stylePreprocessorOptions & hammer min to ng c…
jackofdiamond5 Dec 5, 2023
e205336
refactor(projects): add custom elements schema for dm
jackofdiamond5 Dec 5, 2023
f06382d
refactor(file-update): add components' imports in its metadata
jackofdiamond5 Dec 5, 2023
6c0fcf8
refactor(templates): conditionally include tree grid's custom imports
jackofdiamond5 Dec 5, 2023
0df5760
refactor(templates): conditionally includee custom grid's imports
jackofdiamond5 Dec 6, 2023
8e02065
refactor(templates): conditionally include custom hgrid's imports
jackofdiamond5 Dec 6, 2023
89927ef
chore(*): fix lint
jackofdiamond5 Dec 6, 2023
fbc9358
test(*): update specs
jackofdiamond5 Dec 6, 2023
b8f36c3
refactor(templates): update charts imports
jackofdiamond5 Dec 7, 2023
e12a86b
Merge branch 'master' into bpenkov/standalone-components
Lipata Dec 8, 2023
c14d042
refactor(templates): update dm template
jackofdiamond5 Dec 8, 2023
c2ba933
refactor(projects): add router outlet to empty project
jackofdiamond5 Dec 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 12 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,15 @@ root = true

# Tab indentation (no size specified)
[*.js]
indent_style = tab
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.ts]
quote_type = single

[*.md]
max_line_length = off
trim_trailing_whitespace = false
2 changes: 1 addition & 1 deletion packages/cli/templates/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AngularFramework implements Framework {
this.id = "angular";
this.name = "Angular";
this.projectLibraries = [];
this.projectLibraries.push(require("@igniteui/angular-templates").default as ProjectLibrary);
this.projectLibraries.push(...require("@igniteui/angular-templates").default as ProjectLibrary[]);
this.projectLibraries.push(require("./ig-ts") as ProjectLibrary);
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/core/types/TemplateDependency.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ export interface TemplateDependency {

/** Add an identifier into `ngModule` exports metadata */
export?: string | string[];

/** Describes a dependency for a standalone component's meta */
standalone?: boolean;
}
66 changes: 64 additions & 2 deletions packages/core/typescript/TypeScriptFileUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class TypeScriptFileUpdate {
private requestedImports: Array<{ from: string, imports: string[], edit: boolean }>;
private ngMetaEdits: {
declarations: string[],
imports: Array<{ name: string, root: boolean }>,
imports: Array<{ name: string, root: boolean, standalone?: boolean }>,
providers: string[],
exports: string[]
};
Expand All @@ -42,9 +42,14 @@ export class TypeScriptFileUpdate {
if (this.requestedImports.filter(x => x.edit).length) {
transforms.push(this.importsTransformer);
}
if (Object.keys(this.ngMetaEdits).filter(x => this.ngMetaEdits[x].length).length) {

// should we support both standalone and module-based components in the same app?
if (this.ngMetaEdits.imports.some(x => x.standalone)) {
transforms.push(this.componentMetaTransformer);
} else if (Object.keys(this.ngMetaEdits).filter(x => this.ngMetaEdits[x].length).length) {
transforms.push(this.ngModuleTransformer);
}

if (transforms.length) {
this.targetSource = ts.transform(this.targetSource, transforms).transformed[0];
}
Expand Down Expand Up @@ -137,6 +142,26 @@ export class TypeScriptFileUpdate {
this.ngMetaEdits.exports.push(...exportsArr);
}

/**
* Updates a standalone component's imports metadata.
*/
public addStandaloneImport(dep: TemplateDependency, variables?: { [key: string]: string }) {
const copy = {
import: this.asArray(dep.import, variables),
provide: this.asArray(dep.provide, variables)
};
if (dep.from) {
// request import
const identifiers = [...copy.import, ...copy.provide];
this.requestImport(identifiers, Util.applyConfigTransformation(dep.from, variables));
}

const imports = copy.import
.map(x => ({ name: x, root: dep.root, standalone: true }))
.filter(x => !this.ngMetaEdits.imports.find(i => i.name === x.name));
this.ngMetaEdits.imports.push(...imports);
}

//#region File state

/** Initializes existing imports info, [re]sets import and `NgModule` edits */
Expand Down Expand Up @@ -496,6 +521,43 @@ export class TypeScriptFileUpdate {
return ts.visitNode(rootNode, visitor);
}

// TODO: extend to allow the modification of multiple metadata properties
/** Transformation to apply `this.ngMetaEdits` to a standalone `Component` metadata imports */
protected componentMetaTransformer: ts.TransformerFactory<ts.Node> =
<T extends ts.Node>(context: ts.TransformationContext) => (rootNode: T) => {
const visitComponent: ts.Visitor = (node: ts.Node): ts.Node => {
let importsExpr = null;
const prop = "imports";
if (node.kind === ts.SyntaxKind.ObjectLiteralExpression &&
node.parent &&
node.parent.kind === ts.SyntaxKind.CallExpression) {
const obj = (node as ts.ObjectLiteralExpression);
const objProperties = ts.visitNodes(obj.properties, visitor);
const newProps = [];
const importDeps = this.ngMetaEdits.imports;
importsExpr = ts.factory.createArrayLiteralExpression(
importDeps.map(x => TsUtils.createIdentifier(x.name))
);
newProps.push(ts.factory.createPropertyAssignment(prop, importsExpr));
return context.factory.updateObjectLiteralExpression(obj, [
...objProperties,
...newProps
]);
} else {
node = ts.visitEachChild(node, visitComponent, context);
}

return node;
};
const visitCondition: (node: ts.Node) => boolean = (node: ts.Node) => {
return node.kind === ts.SyntaxKind.CallExpression &&
node.parent && node.parent.kind === ts.SyntaxKind.Decorator &&
(node as ts.CallExpression).expression.getText() === "Component";
};
const visitor = this.createVisitor(visitComponent, visitCondition, context);
return ts.visitNode(rootNode, visitor);
}

//#endregion ts.TransformerFactory

//#region Formatting
Expand Down
51 changes: 47 additions & 4 deletions packages/igx-templates/IgniteUIForAngularTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class IgniteUIForAngularTemplate implements Template {
return Promise.resolve(false);
}

return Object.assign({}, options["extraConfig"], this.getBaseVariables(name));
return Object.assign({}, options["extraConfig"], this.getBaseVariables(name));
}

//TODO: rename name to fullName for clarity + in all other places fileName to fullName
Expand All @@ -62,7 +62,47 @@ export class IgniteUIForAngularTemplate implements Template {
// tslint:disable-next-line:no-submodule-imports
require("@igniteui/cli-core/typescript").TypeScriptFileUpdate;

if (!(options && options.skipRoute) && App.container.get<IFileSystem>(FS_TOKEN).fileExists("src/app/app-routing.module.ts")) {
// standalone components
const mainModulePath = path.join(projectPath, `src/app/${modulePath}`);
if (!this.fileExists(mainModulePath)) {
const appRoutesPath = "src/app/app.routes.ts";
const folderName = this.folderName(name);
const fileName = this.fileName(name);
if (!(options && options.skipRoute) && this.fileExists(appRoutesPath)) {
const rountesConfig = new TsUpdate(path.join(projectPath, appRoutesPath));
rountesConfig.addRoute(
path.join(projectPath, `src/app/${folderName}/${fileName}.component.ts`),
this.fileName(name), //path
Util.nameFromPath(name) //text
);
}

const componentFile = new TsUpdate(path.join(projectPath, `src/app/${folderName}/${fileName}.component.ts`));
for (const dep of this.dependencies) {
if (dep.from && dep.from.startsWith(".")) {
// relative file dependency
const copy = Object.assign({}, dep);
copy.from = Util.relativePath(
path.join(projectPath, `src/app/${folderName}/${fileName}.component.ts`),
path.join(projectPath, copy.from!),
true,
true);
// can use addNgModuleMeta here instead?
componentFile.addStandaloneImport(copy,
Util.applyDelimiters(this.getBaseVariables(name), this.delimiters.content));
continue;
}

componentFile.addStandaloneImport(dep,
Util.applyDelimiters(this.getBaseVariables(name), this.delimiters.content));
}

componentFile.finalize();
return;
}

// ngModule based components
if (!(options && options.skipRoute) && this.fileExists("src/app/app-routing.module.ts")) {
//1) import the component class name,
//2) and populate the Routes array with the path and component
//for example: { path: 'combo', component: ComboComponent }
Expand All @@ -76,7 +116,6 @@ export class IgniteUIForAngularTemplate implements Template {

//3) add an import of the component class from its file location.
//4) populate the declarations portion of the @NgModule with the component class name.
const mainModulePath = path.join(projectPath, `src/app/${modulePath}`);
const mainModule = new TsUpdate(mainModulePath);
this.addClassDeclaration(mainModule, projectPath, name, modulePath);

Expand All @@ -85,7 +124,7 @@ export class IgniteUIForAngularTemplate implements Template {
if (dep.from && dep.from.startsWith(".")) {
// relative file dependency
const copy = Object.assign({}, dep);
copy.from = Util.relativePath(mainModulePath, path.join(projectPath, copy.from), true, true);
copy.from = Util.relativePath(mainModulePath, path.join(projectPath, copy.from!), true, true);
mainModule.addNgModuleMeta(copy,
Util.applyDelimiters(this.getBaseVariables(name), this.delimiters.content));
} else {
Expand All @@ -101,6 +140,10 @@ export class IgniteUIForAngularTemplate implements Template {
}
public setExtraConfiguration(extraConfigKeys: {}) { }

public fileExists(filePath: string): boolean {
return App.container.get<IFileSystem>(FS_TOKEN).fileExists(filePath);
}

protected addClassDeclaration(mainModule: TypeScriptFileUpdate, projPath: string, name: string, modulePath: string) {
mainModule.addDeclaration(
path.join(projPath, `src/app/${this.folderName(name)}/${this.fileName(name)}.component.ts`),
Expand Down
1 change: 1 addition & 0 deletions packages/igx-templates/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const IGNITEUI_ANGULAR_PACKAGE = "igniteui-angular@~17.0.0";
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<p>igx-accordion component sample.</p>
<p>You can read more about configuring the igx-tabs component in the
<a href="https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/accordion/README.md" target="_blank">README</a> or the
<a href="https://www.infragistics.com/products/ignite-ui-angular/angular/components/accordion" target="_blank">official documentation</a>.</p>
<igx-switch [(ngModel)]="singleBranchExpand">Single Branch Expand</igx-switch>
<article class="sample-wrapper">
<igx-accordion #accordion [singleBranchExpand]="singleBranchExpand">
<igx-expansion-panel>
<igx-expansion-panel-header class="expansion-header">
<igx-expansion-panel-title>What has changed about subscription and pricing model?
</igx-expansion-panel-title>
</igx-expansion-panel-header>
<igx-expansion-panel-body>
We have moved to a subscription-based pricing model for all our developer tools. This makes it easier
for you to manage your license subscriptions and allows us to provide a better level of service for you.

We updated our pricing and packages to provide you with flexible options and the best value. This
includes <a href="https://www.infragistics.com/products/ignite-ui">Ignite UI </a>(formerly Ignite UI for
JavaScript) which includes all of our JavaScript framework
components for web development, including: Angular, ASP.NET (Core and MVC), Blazor, JQuery, React and
Web Components), as well as Infragistics Professional, Infragistics Ultimate, our Ultimate UI products.

We also offer multi-year subscriptions options with a built-in discount, so you can see the value up
front. With these updates we are confident that we are providing the best platforms and the best price.
</igx-expansion-panel-body>
</igx-expansion-panel>
<igx-expansion-panel>
<igx-expansion-panel-header class="expansion-header">
<igx-expansion-panel-title>Who will the updated changes impact?</igx-expansion-panel-title>
</igx-expansion-panel-header>
<igx-expansion-panel-body>
The license updates will impact all new and current customers using Ignite UI, Infragistics Professional
and Infragistics Ultimate. Specifically, we have also made updates to our product and packaging for
Ignite UI for JavaScript, Ignite UI for Angular, Ignite UI for React and Ignite UI for Web components.
For more information, please refer to this blog:

<a
href="https://www.infragistics.com/community/blogs/b/jason_beres/posts/announcement-changes-to-ignite-ui-product-packaging">Announcement:
Changes to Ignite UI Product & Packaging</a>

The pricing has been updated for all products and packages. So, all new or additional licenses will be
sold based on our new pricing and packages. All existing license agreements will be honored and renewed
based upon the current agreement.
</igx-expansion-panel-body>
</igx-expansion-panel>
<igx-expansion-panel>
<igx-expansion-panel-header class="expansion-header">
<igx-expansion-panel-title>What is the difference between your old model and your current subscription
model
for Ignite UI?</igx-expansion-panel-title>
</igx-expansion-panel-header>
<igx-expansion-panel-body>
For Ignite UI customers, we are moving away from NPM for licensed packages. The current NPM packages
will be replaced with packages that include a “Trial Version” watermark. Licensed packages for Ignite UI
will be available from our cloud hosted ProGet server.

For more information, please refer to this article:

<a
href="https://www.infragistics.com/products/ignite-ui-angular/angular/components/general/ignite-ui-licensing">Moving
from Trial to Licensed Ignite UI NPM Packages</a>
</igx-expansion-panel-body>
</igx-expansion-panel>
<igx-expansion-panel>
<igx-expansion-panel-header class="expansion-header">
<igx-expansion-panel-title>What happens if I don’t renew my subscription?</igx-expansion-panel-title>
</igx-expansion-panel-header>
<igx-expansion-panel-body>
Any unlicensed or trial versions of Ignite UI for Angular, React and Web Components will now include
this watermark.
</igx-expansion-panel-body>
</igx-expansion-panel>
<igx-expansion-panel>
<igx-expansion-panel-header class="expansion-header">
<igx-expansion-panel-title>If I don’t renew my subscription will I still have access to previous
versions of
Infragistics products?</igx-expansion-panel-title>
</igx-expansion-panel-header>
<igx-expansion-panel-body>
Any version of Infragistics software which you have downloaded can continue to be used perpetually.
Access to download any new or previous versions through our customer portal and package feeds will
require maintaining an active subscription by continuing to renew it.
</igx-expansion-panel-body>
</igx-expansion-panel>
</igx-accordion>
</article>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
$ep-sample-border: 1px solid rgba(174, 174, 174, 0.25);

.sample-wrapper {
overflow-y: auto;
max-height: 450px;
width: 600px;
margin: 8px;
}

igx-expansion-panel-body,
igx-switch {
padding: 16px;
}

igx-expansion-panel {
border: $ep-sample-border;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { <%=ClassName%>Component } from './<%=filePrefix%>.component';
import { IgxAccordionModule, IgxSwitchModule } from '<%=igxPackage%>';

describe('<%=ClassName%>Component', () => {
let component: <%=ClassName%>Component;
let fixture: ComponentFixture<<%=ClassName%>Component>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [<%=ClassName%>Component],
imports: [ NoopAnimationsModule, IgxAccordionModule, IgxSwitchModule ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(<%=ClassName%>Component);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Component } from '@angular/core';

@Component({
selector: 'app-<%=filePrefix%>',
templateUrl: './<%=filePrefix%>.component.html',
styleUrls: ['./<%=filePrefix%>.component.scss']
})
export class <%=ClassName%>Component {
public singleBranchExpand = false;
}
19 changes: 19 additions & 0 deletions packages/igx-templates/igx-ts-legacy/accordion/default/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IgniteUIForAngularTemplate } from "../../../IgniteUIForAngularTemplate";

class IgxAccordionTemplate extends IgniteUIForAngularTemplate {
constructor() {
super(__dirname);
this.components = ["Accordion"];
this.controlGroup = "Layouts";
this.listInComponentTemplates = true;
this.id = "accordion";
this.projectType = "igx-ts";
this.name = "Accordion";
this.description = "Basic IgxAccordion sample";
this.dependencies = [{
import: ["IgxAccordionModule", "IgxSwitchModule"],
from: "<%=igxPackage%>"
}];
}
}
module.exports = new IgxAccordionTemplate();
15 changes: 15 additions & 0 deletions packages/igx-templates/igx-ts-legacy/accordion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

import { BaseComponent } from "@igniteui/cli-core";

class IgxAccordionComponent extends BaseComponent {
/**
*
*/
constructor() {
super(__dirname);
this.name = "Accordion";
this.group = "Layouts";
this.description = `allows users to navigate among multiple collapsible panels displayed in a single container`;
}
}
module.exports = new IgxAccordionComponent();
Loading
Loading