]>
Commit | Line | Data |
---|---|---|
67ed6552 C |
1 | import { Subject } from 'rxjs' |
2 | import { debounceTime, distinctUntilChanged } from 'rxjs/operators' | |
6702a1b2 | 3 | import { Component, OnInit } from '@angular/core' |
6702a1b2 | 4 | import { ActivatedRoute, Router } from '@angular/router' |
67ed6552 | 5 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' |
c96e457b | 6 | import { ComponentPagination, ConfirmService, hasMoreItems, Notifier, PluginService } from '@app/core' |
428ccb8b | 7 | import { PeerTubePluginIndex, PluginType } from '@shared/models' |
d00dc28d C |
8 | |
9 | @Component({ | |
10 | selector: 'my-plugin-search', | |
11 | templateUrl: './plugin-search.component.html', | |
dba85a1e C |
12 | styleUrls: [ |
13 | '../shared/toggle-plugin-type.scss', | |
14 | './plugin-search.component.scss' | |
15 | ] | |
d00dc28d C |
16 | }) |
17 | export class PluginSearchComponent implements OnInit { | |
18 | pluginTypeOptions: { label: string, value: PluginType }[] = [] | |
6702a1b2 C |
19 | pluginType: PluginType = PluginType.PLUGIN |
20 | ||
21 | pagination: ComponentPagination = { | |
22 | currentPage: 1, | |
440d39c5 C |
23 | itemsPerPage: 10, |
24 | totalItems: null | |
6702a1b2 C |
25 | } |
26 | sort = '-popularity' | |
27 | ||
28 | search = '' | |
29 | isSearching = false | |
30 | ||
31 | plugins: PeerTubePluginIndex[] = [] | |
32 | installing: { [name: string]: boolean } = {} | |
89c344db | 33 | pluginInstalled = false |
6702a1b2 | 34 | |
ad453580 C |
35 | onDataSubject = new Subject<any[]>() |
36 | ||
6702a1b2 | 37 | private searchSubject = new Subject<string>() |
d00dc28d C |
38 | |
39 | constructor ( | |
c96e457b | 40 | private pluginService: PluginService, |
078b4716 | 41 | private pluginApiService: PluginApiService, |
6702a1b2 C |
42 | private notifier: Notifier, |
43 | private confirmService: ConfirmService, | |
44 | private router: Router, | |
45 | private route: ActivatedRoute | |
d00dc28d | 46 | ) { |
078b4716 | 47 | this.pluginTypeOptions = this.pluginApiService.getPluginTypeOptions() |
d00dc28d C |
48 | } |
49 | ||
50 | ngOnInit () { | |
6702a1b2 C |
51 | const query = this.route.snapshot.queryParams |
52 | if (query['pluginType']) this.pluginType = parseInt(query['pluginType'], 10) | |
53 | ||
54 | this.searchSubject.asObservable() | |
55 | .pipe( | |
56 | debounceTime(400), | |
57 | distinctUntilChanged() | |
58 | ) | |
59 | .subscribe(search => { | |
60 | this.search = search | |
61 | this.reloadPlugins() | |
62 | }) | |
63 | ||
64 | this.reloadPlugins() | |
65 | } | |
66 | ||
be27ef3b C |
67 | onSearchChange (event: Event) { |
68 | const target = event.target as HTMLInputElement | |
69 | ||
70 | this.searchSubject.next(target.value) | |
6702a1b2 C |
71 | } |
72 | ||
73 | reloadPlugins () { | |
74 | this.pagination.currentPage = 1 | |
75 | this.plugins = [] | |
76 | ||
77 | this.router.navigate([], { queryParams: { pluginType: this.pluginType } }) | |
78 | ||
79 | this.loadMorePlugins() | |
80 | } | |
81 | ||
82 | loadMorePlugins () { | |
83 | this.isSearching = true | |
84 | ||
078b4716 | 85 | this.pluginApiService.searchAvailablePlugins(this.pluginType, this.pagination, this.sort, this.search) |
1378c0d3 C |
86 | .subscribe({ |
87 | next: res => { | |
6702a1b2 C |
88 | this.isSearching = false |
89 | ||
90 | this.plugins = this.plugins.concat(res.data) | |
91 | this.pagination.totalItems = res.total | |
ad453580 C |
92 | |
93 | this.onDataSubject.next(res.data) | |
6702a1b2 C |
94 | }, |
95 | ||
1378c0d3 | 96 | error: err => { |
f0c5e8b6 C |
97 | console.error(err) |
98 | ||
66357162 | 99 | const message = $localize`The plugin index is not available. Please retry later.` |
f0c5e8b6 C |
100 | this.notifier.error(message) |
101 | } | |
1378c0d3 | 102 | }) |
6702a1b2 C |
103 | } |
104 | ||
105 | onNearOfBottom () { | |
106 | if (!hasMoreItems(this.pagination)) return | |
107 | ||
108 | this.pagination.currentPage += 1 | |
109 | ||
110 | this.loadMorePlugins() | |
111 | } | |
112 | ||
113 | isInstalling (plugin: PeerTubePluginIndex) { | |
114 | return !!this.installing[plugin.npmName] | |
115 | } | |
116 | ||
c96e457b C |
117 | getShowRouterLink (plugin: PeerTubePluginIndex) { |
118 | return [ '/admin', 'plugins', 'show', this.pluginService.nameToNpmName(plugin.name, this.pluginType) ] | |
119 | } | |
120 | ||
121 | isThemeSearch () { | |
122 | return this.pluginType === PluginType.THEME | |
123 | } | |
124 | ||
6702a1b2 C |
125 | async install (plugin: PeerTubePluginIndex) { |
126 | if (this.installing[plugin.npmName]) return | |
127 | ||
128 | const res = await this.confirmService.confirm( | |
66357162 C |
129 | $localize`Please only install plugins or themes you trust, since they can execute any code on your instance.`, |
130 | $localize`Install ${plugin.name}?` | |
6702a1b2 C |
131 | ) |
132 | if (res === false) return | |
133 | ||
134 | this.installing[plugin.npmName] = true | |
135 | ||
078b4716 | 136 | this.pluginApiService.install(plugin.npmName) |
1378c0d3 C |
137 | .subscribe({ |
138 | next: () => { | |
6702a1b2 | 139 | this.installing[plugin.npmName] = false |
89c344db | 140 | this.pluginInstalled = true |
6702a1b2 | 141 | |
66357162 | 142 | this.notifier.success($localize`${plugin.name} installed.`) |
6702a1b2 C |
143 | |
144 | plugin.installed = true | |
145 | }, | |
146 | ||
1378c0d3 C |
147 | error: err => this.notifier.error(err.message) |
148 | }) | |
d00dc28d C |
149 | } |
150 | } |