2.48.0 • Published 4 months ago

@memberjunction/ng-file-storage v2.48.0

Weekly downloads
-
License
ISC
Repository
-
Last release
4 months ago

@memberjunction/ng-file-storage

Angular components for managing file storage in MemberJunction applications. This package provides a complete file management system with categories, file upload, and grid display capabilities integrated with MemberJunction's file storage providers.

Features

  • Category Management: Create, rename, and organize file categories in a tree structure
  • File Grid: Display files with sorting, filtering and pagination
  • File Upload: Easy file uploading with progress tracking
  • File Operations: Download, delete, and edit file metadata
  • Drag and Drop: Move files between categories with drag and drop support
  • Integration: Seamless integration with MemberJunction's file storage system
  • Provider Support: Works with multiple file storage providers (Azure Blob, AWS S3, etc.)
  • Overwrite Protection: Confirmation dialog when overwriting existing files
  • Status Management: Track file upload status (Pending, Uploaded, Failed)
  • Type Safety: Full TypeScript support with MemberJunction entities

Installation

npm install @memberjunction/ng-file-storage

Note: This package requires Angular 18.0.2 or later and the following MemberJunction packages:

  • @memberjunction/core (^2.43.0)
  • @memberjunction/core-entities (^2.43.0)
  • @memberjunction/global (^2.43.0)
  • @memberjunction/graphql-dataprovider (^2.43.0)

Prerequisites

Before using this package, ensure your MemberJunction database has:

  • File Storage Providers configured and active
  • File Categories entity permissions for users
  • Files entity permissions for users
  • Proper GraphQL endpoints configured

Usage

Import the Module

import { FileStorageModule } from '@memberjunction/ng-file-storage';

@NgModule({
  imports: [
    FileStorageModule,
    // other imports
  ],
  // ...
})
export class YourModule { }

Basic Component Usage

<!-- File management interface with category tree and file grid -->
<div class="file-manager-container">
  <div class="category-panel">
    <mj-files-category-tree
      (categorySelected)="selectedCategoryId = $event">
    </mj-files-category-tree>
  </div>
  
  <div class="files-panel">
    <mj-files-grid
      [CategoryID]="selectedCategoryId">
    </mj-files-grid>
  </div>
</div>

File Upload Component

<!-- Standalone file upload component -->
<mj-files-file-upload
  [CategoryID]="selectedCategoryId"
  (uploadStarted)="handleUploadStarted()"
  (fileUpload)="handleFileUploaded($event)">
</mj-files-file-upload>

TypeScript Component Example

import { Component } from '@angular/core';
import { FileUploadEvent } from '@memberjunction/ng-file-storage';
import { SharedService } from '@memberjunction/ng-shared';

@Component({
  selector: 'app-document-manager',
  template: `
    <h2>Document Manager</h2>
    
    <div class="file-manager">
      <div class="categories">
        <h3>Categories</h3>
        <mj-files-category-tree
          (categorySelected)="onCategorySelected($event)">
        </mj-files-category-tree>
      </div>
      
      <div class="files">
        <h3>Files in {{ currentCategoryName || 'All Categories' }}</h3>
        <mj-files-grid
          [CategoryID]="selectedCategoryId">
        </mj-files-grid>
      </div>
    </div>
  `,
  styles: [`
    .file-manager {
      display: flex;
      height: 600px;
    }
    .categories {
      width: 300px;
      border-right: 1px solid #ccc;
      padding-right: 20px;
    }
    .files {
      flex: 1;
      padding-left: 20px;
    }
  `]
})
export class DocumentManagerComponent {
  selectedCategoryId?: string;
  currentCategoryName?: string;
  
  constructor(private sharedService: SharedService) {}
  
  onCategorySelected(categoryId?: string) {
    this.selectedCategoryId = categoryId;
    // You could load the category name here if needed
  }
  
  handleFileUploaded(event: FileUploadEvent) {
    if (event.success) {
      this.sharedService.CreateSimpleNotification(
        `File "${event.file.Name}" uploaded successfully`,
        'success'
      );
    } else {
      this.sharedService.CreateSimpleNotification(
        `Failed to upload file "${event.file.name}"`,
        'error'
      );
    }
  }
}

Component Reference

CategoryTreeComponent (mj-files-category-tree)

A tree view component for managing file categories.

Selector

selector: 'mj-files-category-tree'

Outputs

OutputTypeDescription
categorySelectedEventEmitter<string \| undefined>Emitted when a category is selected in the tree

Public Methods

MethodDescriptionParametersReturns
createNewCategory()Opens dialog to create a new categoryNonePromise<void>
deleteCategory(fileCategory: FileCategoryEntity)Deletes a category with error handlingfileCategory: FileCategoryEntityPromise<void>
handleDrop(e: TreeItemAddRemoveArgs)Handles drag and drop to move categoriese: TreeItemAddRemoveArgsPromise<void>
Refresh()Refreshes the category tree dataNonePromise<void>
clearSelection()Clears the current selectionNonevoid
saveNewCategory()Saves a new categoryNonePromise<void>
saveRename()Saves category renameNonePromise<void>
cancelRename()Cancels category renameNonevoid

FilesGridComponent (mj-files-grid)

A grid component for displaying and managing files with support for inline editing and file operations.

Selector

selector: 'mj-files-grid'

Inputs

InputTypeDescriptionDefault
CategoryIDstring \| undefinedThe ID of the category to filter files byundefined

Public Methods

MethodDescriptionParametersReturns
downloadFile(file: FileEntity)Downloads file using provider's download URLfile: FileEntityPromise<void>
deleteFile(file: FileEntity)Deletes file with confirmationfile: FileEntityPromise<void>
saveEditFile()Saves changes to file metadataNonePromise<void>
resetEditFile()Cancels editing file metadataNonevoid
handleFileUpload(e: FileUploadEvent)Handles file upload eventse: FileUploadEventvoid
canBeDeleted(file: FileEntity)Checks if file can be deletedfile: FileEntityboolean
Refresh()Refreshes the files grid dataNonePromise<void>

FileUploadComponent (mj-files-file-upload)

A component for uploading files with provider integration and overwrite protection.

Selector

selector: 'mj-files-file-upload'

Inputs

InputTypeDescriptionDefault
disabledbooleanWhether the upload component is disabledfalse
CategoryIDstring \| undefinedThe category ID to assign to uploaded filesundefined

Outputs

OutputTypeDescription
uploadStartedEventEmitter<void>Emitted when file upload starts
fileUploadEventEmitter<FileUploadEvent>Emitted when a file is uploaded (success or failure)

Public Methods

MethodDescriptionParametersReturns
Confirm()Confirms file overwrite and proceeds with uploadNonevoid
CancelConfirm()Cancels file overwrite and deletes pending recordNonePromise<void>
Refresh()Loads default file storage providerNonePromise<void>
SelectEventHandler(e: SelectEvent)Handles file selectione: SelectEventPromise<void>

Properties

PropertyTypeDescription
IsUploadingbooleanIndicates if files are currently being uploaded

Types

FileUploadEvent

export type FileUploadEvent = 
  | { success: true; file: FileEntity }
  | { success: false; file: FileInfo };

This type represents the result of a file upload operation, containing either a successful FileEntity or a failed FileInfo object.

File Upload Flow

  1. User selects a file using the file upload component
  2. Component creates a preliminary file record in the MemberJunction system
  3. If a file with the same name exists, a confirmation dialog is shown
  4. On confirmation, the file is uploaded to the storage provider
  5. After successful upload, the file record status is updated to "Uploaded"
  6. The component emits a fileUpload event with success status and file details

Styling

The components use Kendo UI components for consistent styling and include basic CSS that can be overridden in your application.

Advanced Usage

Custom File Grid with Actions

import { Component, ViewChild } from '@angular/core';
import { FilesGridComponent, FileUploadEvent } from '@memberjunction/ng-file-storage';
import { FileEntity } from '@memberjunction/core-entities';

@Component({
  template: `
    <div class="file-manager">
      <div class="toolbar">
        <button (click)="refreshFiles()">Refresh</button>
        <mj-files-file-upload 
          [CategoryID]="categoryId"
          (fileUpload)="onFileUploaded($event)">
        </mj-files-file-upload>
      </div>
      
      <mj-files-grid #filesGrid
        [CategoryID]="categoryId">
      </mj-files-grid>
    </div>
  `
})
export class CustomFileManagerComponent {
  @ViewChild('filesGrid') filesGrid!: FilesGridComponent;
  categoryId = 'some-category-id';
  
  refreshFiles() {
    this.filesGrid.Refresh();
  }
  
  onFileUploaded(event: FileUploadEvent) {
    if (event.success) {
      console.log('File uploaded:', event.file.Name);
      // The grid automatically adds the file, no refresh needed
    }
  }
}

Programmatic Category Management

import { Component, ViewChild } from '@angular/core';
import { CategoryTreeComponent } from '@memberjunction/ng-file-storage';
import { Metadata } from '@memberjunction/core';
import { FileCategoryEntity } from '@memberjunction/core-entities';

@Component({
  template: `
    <mj-files-category-tree #categoryTree
      (categorySelected)="onCategorySelected($event)">
    </mj-files-category-tree>
  `
})
export class CategoryManagerComponent {
  @ViewChild('categoryTree') categoryTree!: CategoryTreeComponent;
  
  async createCategoryProgrammatically(name: string, parentId?: string) {
    const md = new Metadata();
    const category = await md.GetEntityObject<FileCategoryEntity>('File Categories');
    category.NewRecord();
    category.Name = name;
    category.ParentID = parentId;
    
    if (await category.Save()) {
      // Refresh the tree to show new category
      await this.categoryTree.Refresh();
    }
  }
  
  onCategorySelected(categoryId?: string) {
    console.log('Selected category:', categoryId);
  }
}

Module Exports

The FileStorageModule exports the following components:

  • CategoryTreeComponent
  • FilesGridComponent
  • FileUploadComponent

Dependencies

MemberJunction Dependencies

  • @memberjunction/core (^2.43.0): Core metadata and entity access
  • @memberjunction/core-entities (^2.43.0): File-related entity types
  • @memberjunction/global (^2.43.0): Global utilities
  • @memberjunction/graphql-dataprovider (^2.43.0): GraphQL data operations
  • @memberjunction/ng-container-directives (^2.43.0): Container directives
  • @memberjunction/ng-shared (^2.43.0): Shared Angular services

Kendo UI Dependencies

  • @progress/kendo-angular-buttons (^16.2.0)
  • @progress/kendo-angular-dialog (^16.2.0)
  • @progress/kendo-angular-dropdowns (^16.2.0)
  • @progress/kendo-angular-grid (^16.2.0)
  • @progress/kendo-angular-indicators (^16.2.0)
  • @progress/kendo-angular-menu (^16.2.0)
  • @progress/kendo-angular-treeview (^16.2.0)
  • @progress/kendo-angular-upload (^16.2.0)

Other Dependencies

  • tslib (^2.3.0)
  • zod (^3.23.4): Schema validation

Build and Development

Building the Package

cd packages/Angular/Generic/file-storage
npm run build

Watch Mode

npm run watch

Integration with MemberJunction

This package integrates with:

  • File Storage Providers: Automatically uses the highest priority active provider
  • GraphQL API: Uses MemberJunction's GraphQL layer for all operations
  • Entity Framework: Leverages MemberJunction's entity system for type safety
  • Permissions: Respects entity-level permissions for Files and File Categories

Notes

  • File deletion is restricted based on upload status and age (10 minutes for pending files)
  • The component automatically handles file overwrite scenarios with user confirmation
  • All file operations are tracked with status updates (Pending → Uploaded)
  • File download uses provider-specific signed URLs for security
  • Category operations support drag-and-drop reorganization
  • Components include loading states for all async operations
2.27.1

8 months ago

2.23.2

8 months ago

2.46.0

4 months ago

2.23.1

8 months ago

2.27.0

8 months ago

2.34.0

6 months ago

2.30.0

7 months ago

2.19.4

9 months ago

2.19.5

9 months ago

2.19.2

9 months ago

2.19.3

9 months ago

2.19.0

9 months ago

2.19.1

9 months ago

2.15.2

9 months ago

2.34.2

6 months ago

2.34.1

6 months ago

2.15.1

9 months ago

2.38.0

5 months ago

2.45.0

5 months ago

2.22.1

8 months ago

2.22.0

8 months ago

2.41.0

5 months ago

2.22.2

8 months ago

2.26.1

8 months ago

2.26.0

8 months ago

2.33.0

6 months ago

2.18.3

9 months ago

2.18.1

9 months ago

2.18.2

9 months ago

2.18.0

9 months ago

2.37.1

5 months ago

2.37.0

5 months ago

2.14.0

10 months ago

2.21.0

9 months ago

2.44.0

5 months ago

2.40.0

5 months ago

2.29.0

7 months ago

2.29.2

7 months ago

2.29.1

7 months ago

2.25.0

8 months ago

2.48.0

4 months ago

2.32.0

7 months ago

2.32.2

7 months ago

2.32.1

7 months ago

2.17.0

9 months ago

2.13.4

10 months ago

2.36.0

6 months ago

2.13.2

11 months ago

2.13.3

10 months ago

2.13.0

11 months ago

2.36.1

6 months ago

2.13.1

11 months ago

2.43.0

5 months ago

2.20.2

9 months ago

2.20.3

9 months ago

2.20.0

9 months ago

2.20.1

9 months ago

2.28.0

8 months ago

2.47.0

4 months ago

2.24.1

8 months ago

2.24.0

8 months ago

2.31.0

7 months ago

2.12.0

12 months ago

2.39.0

5 months ago

2.16.1

9 months ago

2.35.1

6 months ago

2.35.0

6 months ago

2.16.0

9 months ago

2.42.1

5 months ago

2.42.0

5 months ago

2.23.0

8 months ago

2.11.0

12 months ago

2.10.0

12 months ago

2.9.0

12 months ago

2.8.0

1 year ago

2.6.1

1 year ago

2.6.0

1 year ago

2.7.0

1 year ago

2.5.2

1 year ago

2.7.1

1 year ago

1.8.1

1 year ago

1.8.0

1 year ago

1.6.1

1 year ago

1.6.0

1 year ago

1.4.1

1 year ago

1.4.0

1 year ago

2.2.1

1 year ago

2.2.0

1 year ago

2.4.1

1 year ago

2.4.0

1 year ago

2.0.0

1 year ago

1.7.1

1 year ago

1.5.3

1 year ago

1.7.0

1 year ago

1.5.2

1 year ago

1.5.1

1 year ago

1.3.3

1 year ago

1.5.0

1 year ago

1.3.2

1 year ago

1.3.1

1 year ago

1.3.0

1 year ago

2.3.0

1 year ago

2.1.2

1 year ago

2.1.1

1 year ago

2.5.0

1 year ago

2.3.2

1 year ago

2.1.4

1 year ago

2.3.1

1 year ago

2.1.3

1 year ago

2.5.1

1 year ago

2.3.3

1 year ago

2.1.5

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.1.1

1 year ago

1.1.0

1 year ago

1.1.3

1 year ago

1.1.2

1 year ago

1.0.11

1 year ago

1.0.9

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.8-next.6

2 years ago

1.0.8-next.5

2 years ago

1.0.8-next.4

2 years ago

1.0.8-next.3

2 years ago

1.0.8-next.2

2 years ago

1.0.8-beta.0

2 years ago

1.0.8-next.1

2 years ago

1.0.8-next.0

2 years ago

1.0.7-next.0

2 years ago

1.0.1

2 years ago

1.0.6

2 years ago

1.0.4

2 years ago

0.9.24

2 years ago

0.9.25

2 years ago

0.9.26

2 years ago

0.9.22

2 years ago

0.9.20

2 years ago

0.9.21

2 years ago

0.9.19

2 years ago

0.9.15

2 years ago

0.9.16

2 years ago

0.9.17

2 years ago

0.9.18

2 years ago

0.9.13

2 years ago

0.9.14

2 years ago

0.9.12

2 years ago

0.9.10

2 years ago

0.9.8

2 years ago

0.9.9

2 years ago

0.9.7

2 years ago

0.9.6

2 years ago

0.9.5

2 years ago

0.9.4

2 years ago

0.9.3

2 years ago