# Integration Notes

UnifiedFiler is provided as a reusable package whose extracted root folder is copied into a Host system.
The Host system owns launch, window management, authentication, tenant context, permissions, and app-to-app integration.

## Required OSS loading order

Load OSS libraries globally before `require.js`. Font Awesome is optional; UnifiedFiler falls back to plain text icons when it is not loaded.

```html
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<!-- Optional: enhanced toolbar/context icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
<link rel="stylesheet" href="/assets/unified_filer/themes/default/unified-filer.css">
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
```

## RequireJS path example

The Host should mount the package with one alias.

```javascript
require.config({
    baseUrl: './scripts',
    paths: {
        UnifiedFiler: '/assets/unified_filer/scripts'
    }
});
```

Package-internal modules use relative AMD dependencies. Therefore, Host applications do not need to define separate aliases for `services`, `adapters`, `views`, `utils`, `i18n`, or `vendor`.

## Package entry module

```javascript
require(['UnifiedFiler/main'], function (UnifiedFiler) {
    var StorageRegistry = UnifiedFiler.services.StorageRegistry;
    var FileService = UnifiedFiler.services.FileService;
    var IndexedDbAdapter = UnifiedFiler.adapters.IndexedDbAdapter;
});
```

## Plugin initialization example

```javascript
require([
    'UnifiedFiler/services/StorageRegistry',
    'UnifiedFiler/services/FileService',
    'UnifiedFiler/services/RecentFileService',
    'UnifiedFiler/services/FavoriteFileService',
    'UnifiedFiler/services/MetadataService',
    'UnifiedFiler/services/PreviewService',
    'UnifiedFiler/services/OperationProgressService',
    'UnifiedFiler/adapters/IndexedDbAdapter',
    'UnifiedFiler/adapters/LocalDiskAdapter',
    'UnifiedFiler/adapters/GoogleDriveAdapter',
    'UnifiedFiler/views/FileExplorerView',
    'UnifiedFiler/i18n/ja'
], function (
    StorageRegistry,
    FileService,
    RecentFileService,
    FavoriteFileService,
    MetadataService,
    PreviewService,
    OperationProgressService,
    IndexedDbAdapter,
    LocalDiskAdapter,
    GoogleDriveAdapter,
    FileExplorer,
    i18n
) {
    var registry = new StorageRegistry();
    var appStorage = new IndexedDbAdapter({ id: 'appStorage', label: 'App Storage' });
    var localDisk = new LocalDiskAdapter({ id: 'localDisk', label: 'This Device' });
    var googleDrive = new GoogleDriveAdapter({
        id: 'googleDrive',
        label: 'Google Drive',
        clientId: googleOAuthClientId,
        apiKey: googleApiKey,
        appId: googleAppId,
        scopes: ['https://www.googleapis.com/auth/drive.file'],
        enablePicker: true
    });

    Promise.all([appStorage.init(), localDisk.init()]).then(function () {
        registry.register(appStorage);
        registry.register(localDisk);
        registry.register(googleDrive);

        var progressService = new OperationProgressService();
        var fileService = new FileService({ registry: registry, progressService: progressService });
        var recentFileService = new RecentFileService();
        var favoriteFileService = new FavoriteFileService();
        var metadataService = new MetadataService();
        var previewService = new PreviewService();

        $('#fileExplorer').fileExplorer({
            defaultStorage: 'appStorage',
            storageTypes: ['appStorage', 'localDisk', 'googleDrive'],
            viewMode: 'detail',
            language: 'ja',
            enablePreview: true,
            enableMetadata: true,
            enableRecentFiles: true,
            enableThumbnails: true,
            thumbnailSize: 96,
            enableUpload: true,
            allowMultipleUpload: true,
            readOnly: false,
            showTree: true,
            allowedExtensions: [],
            maxPreviewSize: 1048576,
            folderFirst: true,
            services: {
                fileService: fileService,
                storageRegistry: registry,
                recentFileService: recentFileService,
                favoriteFileService: favoriteFileService,
                metadataService: metadataService,
                previewService: previewService,
                progressService: progressService
            },
            i18n: i18n,
            onEvent: function (name, payload) {
                console.log('[UnifiedFiler]', name, payload);
            }
        });
    });
});
```

## Host integration callbacks

A Host can receive component events either through jQuery events or option callbacks.

```javascript
$('#fileExplorer').on('fileexplorer:openFile', function (event, payload) {
    // Hand off to the Host app launcher or viewer component.
    console.log(payload.entry);
});
```

The common `onEvent(name, payload)` option is useful when the Host wants one event bridge for logging, permission checks, window messaging, or app-to-app integration.

## FilePickerDialog integration example

```javascript
$('#dialogHost').filePickerDialog({
    defaultStorage: 'appStorage',
    storageTypes: ['appStorage', 'localDisk'],
    selectionType: 'file',
    multiple: true,
    allowedExtensions: ['.txt', '.json'],
    acceptMimeTypes: ['text/*', 'application/json'],
    services: {
        fileService: fileService,
        storageRegistry: registry
    },
    onSelect: function (files, state) {
        // Hand off selected files/folders to the Host.
        console.log(files, state);
    }
});
```

## FileSaverDialog integration example

```javascript
$('#dialogHost').fileSaverDialog({
    defaultStorage: 'appStorage',
    defaultFileName: 'untitled.txt',
    storageTypes: ['appStorage', 'localDisk'],
    overwriteMode: 'confirm',
    fileTypes: [
        { label: 'Text File', extension: '.txt', mimeType: 'text/plain' },
        { label: 'JSON File', extension: '.json', mimeType: 'application/json' }
    ],
    services: {
        fileService: fileService,
        storageRegistry: registry
    },
    getData: function (request) {
        return editor.getValue();
    },
    onSaved: function (savedEntry, request) {
        console.log(savedEntry, request);
    }
});
```

If `getData`, `dataProvider`, `data`, or `content` is not supplied, FileSaverDialog uses request-only mode and delegates the actual save workflow to the Host through `onSave(request)`.

## v1.4 local folder mount and progress

`LocalDiskAdapter` can mount a browser-approved local folder when the File System Access API is available. FileExplorer exposes this through the local-folder mount command. `OperationProgressService` is a small event hub for transfer progress and can also be reused by future API-backed adapters.

```javascript
fileService.mountStorage('localDisk', { readOnly: false }).then(function () {
    return fileService.list('localDisk', '/');
});
```

## v1.3 sidecar services

`FavoriteFileService`, `MetadataService`, and `PreviewService` are optional but recommended when the Host wants favorite files, tags/descriptions, cached thumbnails, and shared preview rendering. These services do not replace storage adapters; they store UI-side sidecar information keyed by adapter and file path. A backend implementation can replace them later without changing FileExplorer initialization.



## v1.8.1 Google Drive browser adapter

UnifiedFiler can access Google Drive from browser JavaScript only. The Host supplies OAuth Client ID, API key, App ID and scopes as adapter parameters; no proprietary backend proxy is required.

```javascript
var googleDrive = new UnifiedFiler.adapters.GoogleDriveAdapter({
    id: 'googleDrive',
    label: 'Google Drive',
    tenantId: activeTenantId,
    appId: '<Google App ID>',
    userId: currentUserId,
    clientId: '<OAuth Client ID>',
    apiKey: '<API Key>',
    scopes: ['https://www.googleapis.com/auth/drive.file'],
    enablePicker: true,
    supportsAllDrives: true,
    includeItemsFromAllDrives: true
});

registry.register(googleDrive);
```

The adapter internally creates these services when they are not explicitly supplied:

- `GoogleIdentityAuthService` for Google Identity Services OAuth token flow.
- `GoogleDriveApiService` for Drive API v3 `fetch` calls.
- `GoogleDrivePickerService` for Google Picker.

A Host can still create those services itself and inject them into the adapter when it wants central token handling or custom logging.

```javascript
var auth = new UnifiedFiler.services.GoogleIdentityAuthService({
    clientId: '<OAuth Client ID>',
    scopes: ['https://www.googleapis.com/auth/drive.file']
});
var api = new UnifiedFiler.services.GoogleDriveApiService({
    authService: auth,
    apiKey: '<API Key>'
});
var picker = new UnifiedFiler.services.GoogleDrivePickerService({
    authService: auth,
    apiKey: '<API Key>',
    appId: '<Google App ID>'
});
var googleDrive = new UnifiedFiler.adapters.GoogleDriveAdapter({
    authService: auth,
    apiService: api,
    pickerService: picker
});
```

## v1.6 ZIP/native package inspection

When the Host wants FileExplorer to inspect ZIP-based native packages, load JSZip globally before RequireJS. UnifiedFiler then uses `PackageInfoService` through the normal service injection mechanism.

```javascript
var packageInfoService = new UnifiedFiler.services.PackageInfoService();

$('#fileExplorer').fileExplorer({
    services: {
        fileService: fileService,
        storageRegistry: registry,
        previewService: previewService,
        packageInfoService: packageInfoService
    },
    enablePackagePreview: true,
    packagePreviewMaxEntries: 60
});
```

The supported package extensions are `.zip`, `.uwpsx`, `.usldx`, `.umal`, `.umdlx`, and `.ualbx`. Package inspection reads the selected file through `FileService`, so it works with IndexedDB, local folders, and backend adapters as long as the adapter supports `read`.

## v1.5 Backend API adapter

A Host can register a backend-backed storage adapter without changing FileExplorer, FilePicker, or FileSaver UI code.

```javascript
require([
    'UnifiedFiler/main'
], function (UnifiedFiler) {
    var registry = new UnifiedFiler.services.StorageRegistry();
    var backendApi = new UnifiedFiler.adapters.BackendApiAdapter({
        id: 'backendApi',
        label: 'Backend API',
        baseUrl: '/api',
        endpointRoot: '/filer',
        tenantId: activeTenantId,
        appId: 'UnifiedFiler',
        userId: currentUserId,
        withCredentials: true
    });

    registry.register(backendApi);
});
```

For a browser-only demo or test, the Host can pass `MemoryApiBackendService` as a direct backend object.

```javascript
var memoryBackend = new UnifiedFiler.services.MemoryApiBackendService({
    namespace: 'demo_backend_api'
});

memoryBackend.init().then(function () {
    registry.register(new UnifiedFiler.adapters.BackendApiAdapter({
        id: 'backendApi',
        label: 'Backend API',
        tenantId: 'demo-tenant',
        appId: 'UnifiedFilerDemo',
        userId: 'demo-user',
        backend: memoryBackend
    }));
});
```

## v1.9 Host integration additions

Use `HostIntegrationService` to centralize app associations and standard picker/saver profiles.

```javascript
var integration = new UnifiedFiler.services.HostIntegrationService({
  host: window.AppHost
});

var pickerOptions = integration.createPickerOptions('viewer', {
  storageTypes: ['appStorage', 'googleDrive']
});
```

Recommended profile names:

- `unifiedDesktop`
- `office`
- `viewer`
- `editor`

Use `ConflictResolverService` when a Host wants one conflict policy across local, backend and Google Drive storage adapters.
