Browse Source

feat: 增加忽略应用列表和取消忽略功能 (#1566)

增加忽略应用列表和取消忽略功能
pull/1572/head
zhengkunwang223 1 year ago committed by GitHub
parent
commit
10427ddd65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      backend/app/api/v1/app.go
  2. 4
      backend/app/dto/request/app.go
  3. 7
      backend/app/dto/response/app.go
  4. 8
      backend/app/repo/app_detail.go
  5. 22
      backend/app/service/app.go
  6. 2
      backend/app/service/app_install.go
  7. 1
      backend/router/ro_app.go
  8. 483
      cmd/server/docs/docs.go
  9. 412
      cmd/server/docs/swagger.json
  10. 386
      cmd/server/docs/swagger.yaml
  11. 7
      frontend/src/api/interface/app.ts
  12. 4
      frontend/src/api/modules/app.ts
  13. 5
      frontend/src/lang/modules/en.ts
  14. 5
      frontend/src/lang/modules/tw.ts
  15. 5
      frontend/src/lang/modules/zh.ts
  16. 85
      frontend/src/views/app-store/installed/ignore/index.vue
  17. 17
      frontend/src/views/app-store/installed/index.vue
  18. 6
      go.mod
  19. 6
      go.sum

16
backend/app/api/v1/app.go

@ -130,6 +130,22 @@ func (b *BaseApi) GetAppDetailByID(c *gin.Context) {
helper.SuccessWithData(c, appDetailDTO) helper.SuccessWithData(c, appDetailDTO)
} }
// @Tags App
// @Summary Get Ignore App
// @Description 获取忽略的应用版本
// @Accept json
// @Success 200 {object} response.IgnoredApp
// @Security ApiKeyAuth
// @Router /apps/ingored [get]
func (b *BaseApi) GetIgnoredApp(c *gin.Context) {
res, err := appService.GetIgnoredApp()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, res)
}
// @Tags App // @Tags App
// @Summary Install app // @Summary Install app
// @Description 安装应用 // @Description 安装应用

4
backend/app/dto/request/app.go

@ -67,8 +67,8 @@ type AppInstalledUpdate struct {
} }
type AppInstalledIgnoreUpgrade struct { type AppInstalledIgnoreUpgrade struct {
InstallId uint `json:"installId" validate:"required"` DetailID uint `json:"detailID" validate:"required"`
DetailId uint `json:"detailId" validate:"required"` Operate string `json:"operate" validate:"required,oneof=cancel ignore"`
} }
type PortUpdate struct { type PortUpdate struct {

7
backend/app/dto/response/app.go

@ -48,6 +48,13 @@ type AppDetailDTO struct {
Image string `json:"image"` Image string `json:"image"`
} }
type IgnoredApp struct {
Icon string `json:"icon"`
Name string `json:"name"`
Version string `json:"version"`
DetailID uint `json:"detailID"`
}
type AppInstalledDTO struct { type AppInstalledDTO struct {
model.AppInstall model.AppInstall
Total int `json:"total"` Total int `json:"total"`

8
backend/app/repo/app_detail.go

@ -13,6 +13,7 @@ type AppDetailRepo struct {
type IAppDetailRepo interface { type IAppDetailRepo interface {
WithVersion(version string) DBOption WithVersion(version string) DBOption
WithAppId(id uint) DBOption WithAppId(id uint) DBOption
WithIgnored() DBOption
GetFirst(opts ...DBOption) (model.AppDetail, error) GetFirst(opts ...DBOption) (model.AppDetail, error)
Update(ctx context.Context, detail model.AppDetail) error Update(ctx context.Context, detail model.AppDetail) error
BatchCreate(ctx context.Context, details []model.AppDetail) error BatchCreate(ctx context.Context, details []model.AppDetail) error
@ -31,12 +32,19 @@ func (a AppDetailRepo) WithVersion(version string) DBOption {
return g.Where("version = ?", version) return g.Where("version = ?", version)
} }
} }
func (a AppDetailRepo) WithAppId(id uint) DBOption { func (a AppDetailRepo) WithAppId(id uint) DBOption {
return func(g *gorm.DB) *gorm.DB { return func(g *gorm.DB) *gorm.DB {
return g.Where("app_id = ?", id) return g.Where("app_id = ?", id)
} }
} }
func (a AppDetailRepo) WithIgnored() DBOption {
return func(g *gorm.DB) *gorm.DB {
return g.Where("ignore_upgrade = 1")
}
}
func (a AppDetailRepo) GetFirst(opts ...DBOption) (model.AppDetail, error) { func (a AppDetailRepo) GetFirst(opts ...DBOption) (model.AppDetail, error) {
var detail model.AppDetail var detail model.AppDetail
err := getDb(opts...).Model(&model.AppDetail{}).Find(&detail).Error err := getDb(opts...).Model(&model.AppDetail{}).Find(&detail).Error

22
backend/app/service/app.go

@ -39,6 +39,7 @@ type IAppService interface {
GetAppUpdate() (*response.AppUpdateRes, error) GetAppUpdate() (*response.AppUpdateRes, error)
GetAppDetailByID(id uint) (*response.AppDetailDTO, error) GetAppDetailByID(id uint) (*response.AppDetailDTO, error)
SyncAppListFromLocal() SyncAppListFromLocal()
GetIgnoredApp() ([]response.IgnoredApp, error)
} }
func NewIAppService() IAppService { func NewIAppService() IAppService {
@ -232,6 +233,27 @@ func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
return res, nil return res, nil
} }
func (a AppService) GetIgnoredApp() ([]response.IgnoredApp, error) {
var res []response.IgnoredApp
details, _ := appDetailRepo.GetBy(appDetailRepo.WithIgnored())
if len(details) == 0 {
return res, nil
}
for _, detail := range details {
app, err := appRepo.GetFirst(commonRepo.WithByID(detail.AppId))
if err != nil {
return nil, err
}
res = append(res, response.IgnoredApp{
Name: app.Name,
Version: detail.Version,
DetailID: detail.ID,
Icon: app.Icon,
})
}
return res, nil
}
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (appInstall *model.AppInstall, err error) { func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (appInstall *model.AppInstall, err error) {
if err = docker.CreateDefaultDockerNetwork(); err != nil { if err = docker.CreateDefaultDockerNetwork(); err != nil {
err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil) err = buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)

2
backend/app/service/app_install.go

@ -359,7 +359,7 @@ func (a *AppInstallService) IgnoreUpgrade(req request.AppInstalledIgnoreUpgrade)
if err != nil { if err != nil {
return err return err
} }
appDetail.IgnoreUpgrade = true appDetail.IgnoreUpgrade = req.Operate == "ignore"
return appDetailRepo.Update(context.Background(), appDetail) return appDetailRepo.Update(context.Background(), appDetail)
} }

1
backend/router/ro_app.go

@ -37,5 +37,6 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
appRouter.GET("/installed/params/:appInstallId", baseApi.GetParams) appRouter.GET("/installed/params/:appInstallId", baseApi.GetParams)
appRouter.POST("/installed/params/update", baseApi.UpdateInstalled) appRouter.POST("/installed/params/update", baseApi.UpdateInstalled)
appRouter.POST("/installed/ignore", baseApi.IgnoreUpgrade) appRouter.POST("/installed/ignore", baseApi.IgnoreUpgrade)
appRouter.GET("/ignored/detail", baseApi.GetIgnoredApp)
} }
} }

483
cmd/server/docs/docs.go

File diff suppressed because it is too large Load Diff

412
cmd/server/docs/swagger.json

File diff suppressed because it is too large Load Diff

386
cmd/server/docs/swagger.yaml

File diff suppressed because it is too large Load Diff

7
frontend/src/api/interface/app.ts

@ -187,4 +187,11 @@ export namespace App {
allowPort: boolean; allowPort: boolean;
dockerCompose: string; dockerCompose: string;
} }
export interface IgnoredApp {
name: string;
detailID: number;
version: string;
icon: string;
}
} }

4
frontend/src/api/modules/app.ts

@ -93,3 +93,7 @@ export const UpdateAppInstallParams = (req: any) => {
export const IgnoreUpgrade = (req: any) => { export const IgnoreUpgrade = (req: any) => {
return http.post<any>(`apps/installed/ignore`, req); return http.post<any>(`apps/installed/ignore`, req);
}; };
export const GetIgnoredApp = () => {
return http.get<App.IgnoredApp>(`apps/ignored/detail`);
};

5
frontend/src/lang/modules/en.ts

@ -44,7 +44,7 @@ const message = {
refresh: 'Refresh', refresh: 'Refresh',
get: 'Get', get: 'Get',
upgrade: 'Upgrade', upgrade: 'Upgrade',
ignoreUpgrade: 'Ignore upgrade', ignore: 'Ignore upgrade',
copy: 'Copy', copy: 'Copy',
random: 'Random', random: 'Random',
}, },
@ -1198,6 +1198,9 @@ const message = {
'Currently, if the port external access is not checked, it will not be able to access through the external network IP: port. Do you want to continue?', 'Currently, if the port external access is not checked, it will not be able to access through the external network IP: port. Do you want to continue?',
restoreWarn: restoreWarn:
'The restore operation will delete the current data of the application and restart it. This operation cannot be rolled back, continue?', 'The restore operation will delete the current data of the application and restart it. This operation cannot be rolled back, continue?',
showIgnore: 'View ignore application',
cancelIgnore: 'Cancel ignore',
ignoreList: 'ignore list',
}, },
website: { website: {
website: 'Website', website: 'Website',

5
frontend/src/lang/modules/tw.ts

@ -44,7 +44,7 @@ const message = {
refresh: '刷新', refresh: '刷新',
get: '獲取', get: '獲取',
upgrade: '升級', upgrade: '升級',
ignoreUpgrade: '忽略升級', ignore: '忽略升級',
copy: '復製', copy: '復製',
random: '隨機密碼', random: '隨機密碼',
}, },
@ -1139,6 +1139,9 @@ const message = {
upgradeHelper: '異常應用需要先同步到正常狀態', upgradeHelper: '異常應用需要先同步到正常狀態',
installWarn: '當前未勾選端口外部訪問將無法通過外網IP:端口訪問是否繼續 ', installWarn: '當前未勾選端口外部訪問將無法通過外網IP:端口訪問是否繼續 ',
restoreWarn: '恢復操作將刪除該應用當前數據並重啟此操作不可回滾是否繼續?', restoreWarn: '恢復操作將刪除該應用當前數據並重啟此操作不可回滾是否繼續?',
showIgnore: '查看忽略應用',
cancelIgnore: '取消忽略',
ignoreList: '忽略列表',
}, },
website: { website: {
website: '網站', website: '網站',

5
frontend/src/lang/modules/zh.ts

@ -44,7 +44,7 @@ const message = {
refresh: '刷新', refresh: '刷新',
get: '获取', get: '获取',
upgrade: '升级', upgrade: '升级',
ignoreUpgrade: '忽略升级', ignore: '忽略升级',
copy: '复制', copy: '复制',
random: '随机密码', random: '随机密码',
}, },
@ -1145,6 +1145,9 @@ const message = {
upgradeHelper: '异常应用需要先同步到正常状态', upgradeHelper: '异常应用需要先同步到正常状态',
installWarn: '当前未勾选端口外部访问将无法通过外网IP:端口访问是否继续', installWarn: '当前未勾选端口外部访问将无法通过外网IP:端口访问是否继续',
restoreWarn: '恢复操作将删除该应用当前数据并重启此操作不可回滚是否继续?', restoreWarn: '恢复操作将删除该应用当前数据并重启此操作不可回滚是否继续?',
showIgnore: '查看忽略应用',
cancelIgnore: '取消忽略',
ignoreList: '忽略列表',
}, },
website: { website: {
website: '网站', website: '网站',

85
frontend/src/views/app-store/installed/ignore/index.vue

@ -0,0 +1,85 @@
<template>
<el-drawer :close-on-click-modal="false" v-model="open" size="30%">
<template #header>
<Header :header="$t('app.ignoreList')" :back="handleClose"></Header>
</template>
<el-row :gutter="5">
<el-col v-for="(app, index) in apps" :key="index">
<el-card class="app-margin">
<el-row :gutter="20">
<el-col :span="6">
<el-avatar shape="square" :size="60" :src="'data:image/png;base64,' + app.icon" />
</el-col>
<el-col :span="12">
<span>{{ app.name }}</span>
<div class="app-margin">
<el-tag>{{ app.version }}</el-tag>
</div>
</el-col>
<el-col :span="6">
<el-button type="primary" link @click="cancelIngore(app.detailID)">
{{ $t('app.cancelIgnore') }}
</el-button>
</el-col>
</el-row>
</el-card>
</el-col>
</el-row>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
</span>
</template>
</el-drawer>
</template>
<script lang="ts" setup>
import { GetIgnoredApp, IgnoreUpgrade } from '@/api/modules/app';
import { ref } from 'vue';
import Header from '@/components/drawer-header/index.vue';
import { MsgSuccess } from '@/utils/message';
import i18n from '@/lang';
const open = ref(false);
const loading = ref(false);
const apps = ref();
const em = defineEmits(['close']);
const handleClose = () => {
open.value = false;
em('close', open);
};
const acceptParams = () => {
open.value = true;
getApps();
};
const getApps = async () => {
try {
const res = await GetIgnoredApp();
apps.value = res.data;
} catch (error) {}
};
const cancelIngore = async (id: number) => {
loading.value = true;
await IgnoreUpgrade({ detailID: id, operate: 'cancel' })
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.finally(() => {
getApps();
loading.value = false;
});
};
defineExpose({
acceptParams,
});
</script>
<style scoped>
.app-margin {
margin-top: 10px;
}
</style>

17
frontend/src/views/app-store/installed/index.vue

@ -46,6 +46,9 @@
<el-button @click="sync" type="primary" link v-if="mode === 'installed' && data != null"> <el-button @click="sync" type="primary" link v-if="mode === 'installed' && data != null">
{{ $t('app.sync') }} {{ $t('app.sync') }}
</el-button> </el-button>
<el-button @click="openIngore" type="primary" link v-if="mode === 'upgrade'">
{{ $t('app.showIgnore') }}
</el-button>
</template> </template>
<template #main> <template #main>
@ -164,10 +167,10 @@
plain plain
round round
size="small" size="small"
@click="openOperate(installed, 'ignoreUpgrade')" @click="openOperate(installed, 'ignore')"
v-if="mode === 'upgrade'" v-if="mode === 'upgrade'"
> >
{{ $t('commons.button.ignoreUpgrade') }} {{ $t('commons.button.ignore') }}
</el-button> </el-button>
<el-button <el-button
class="h-button" class="h-button"
@ -239,8 +242,8 @@
<AppDelete ref="deleteRef" @close="search" /> <AppDelete ref="deleteRef" @close="search" />
<AppParams ref="appParamRef" /> <AppParams ref="appParamRef" />
<AppUpgrade ref="upgradeRef" @close="search" /> <AppUpgrade ref="upgradeRef" @close="search" />
<PortJumpDialog ref="dialogPortJumpRef" /> <PortJumpDialog ref="dialogPortJumpRef" />
<AppIgnore ref="ignoreRef" @close="search" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -261,6 +264,7 @@ import AppResources from './check/index.vue';
import AppDelete from './delete/index.vue'; import AppDelete from './delete/index.vue';
import AppParams from './detail/index.vue'; import AppParams from './detail/index.vue';
import AppUpgrade from './upgrade/index.vue'; import AppUpgrade from './upgrade/index.vue';
import AppIgnore from './ignore/index.vue';
import { App } from '@/api/interface/app'; import { App } from '@/api/interface/app';
import Status from '@/components/status/index.vue'; import Status from '@/components/status/index.vue';
import { getAge } from '@/utils/util'; import { getAge } from '@/utils/util';
@ -289,6 +293,7 @@ const checkRef = ref();
const deleteRef = ref(); const deleteRef = ref();
const appParamRef = ref(); const appParamRef = ref();
const upgradeRef = ref(); const upgradeRef = ref();
const ignoreRef = ref();
const dialogPortJumpRef = ref(); const dialogPortJumpRef = ref();
const tags = ref<App.Tag[]>([]); const tags = ref<App.Tag[]>([]);
const activeTag = ref('all'); const activeTag = ref('all');
@ -348,7 +353,7 @@ const goDashboard = async (port: any) => {
const openOperate = (row: any, op: string) => { const openOperate = (row: any, op: string) => {
operateReq.installId = row.id; operateReq.installId = row.id;
operateReq.operate = op; operateReq.operate = op;
if (op == 'upgrade' || op == 'ignoreUpgrade') { if (op == 'upgrade' || op == 'ignore') {
upgradeRef.value.acceptParams(row.id, row.name, op); upgradeRef.value.acceptParams(row.id, row.name, op);
} else if (op == 'delete') { } else if (op == 'delete') {
AppInstalledDeleteCheck(row.id).then(async (res) => { AppInstalledDeleteCheck(row.id).then(async (res) => {
@ -364,6 +369,10 @@ const openOperate = (row: any, op: string) => {
} }
}; };
const openIngore = () => {
ignoreRef.value.acceptParams();
};
const operate = async () => { const operate = async () => {
open.value = false; open.value = false;
loading.value = true; loading.value = true;

6
go.mod

@ -47,7 +47,7 @@ require (
github.com/subosito/gotenv v1.4.1 github.com/subosito/gotenv v1.4.1
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a
github.com/swaggo/gin-swagger v1.5.3 github.com/swaggo/gin-swagger v1.5.3
github.com/swaggo/swag v1.8.4 github.com/swaggo/swag v1.16.1
github.com/tencentyun/cos-go-sdk-v5 v0.7.41 github.com/tencentyun/cos-go-sdk-v5 v0.7.41
github.com/xlzd/gotp v0.0.0-20220817083547-a63b9d03d72f github.com/xlzd/gotp v0.0.0-20220817083547-a63b9d03d72f
golang.org/x/crypto v0.9.0 golang.org/x/crypto v0.9.0
@ -245,11 +245,11 @@ require (
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/image v0.5.0 // indirect golang.org/x/image v0.5.0 // indirect
golang.org/x/mod v0.8.0 // indirect golang.org/x/mod v0.9.0 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/term v0.8.0 // indirect golang.org/x/term v0.8.0 // indirect
golang.org/x/time v0.1.0 // indirect golang.org/x/time v0.1.0 // indirect
golang.org/x/tools v0.6.0 // indirect golang.org/x/tools v0.7.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.53.0 // indirect google.golang.org/grpc v1.53.0 // indirect

6
go.sum

@ -845,6 +845,8 @@ github.com/swaggo/gin-swagger v1.5.3/go.mod h1:3XJKSfHjDMB5dBo/0rrTXidPmgLeqsX89
github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
github.com/swaggo/swag v1.8.4 h1:oGB351qH1JqUqK1tsMYEE5qTBbPk394BhsZxmUfebcI= github.com/swaggo/swag v1.8.4 h1:oGB351qH1JqUqK1tsMYEE5qTBbPk394BhsZxmUfebcI=
github.com/swaggo/swag v1.8.4/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg= github.com/swaggo/swag v1.8.4/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg=
github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4=
@ -1011,6 +1013,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1202,6 +1206,8 @@ golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

Loading…
Cancel
Save